From ae2ae0c8b2a1575954ee928fcb4da31517a63554 Mon Sep 17 00:00:00 2001
From: Martijn Vermaat <martijn@vermaat.name>
Date: Fri, 4 Nov 2011 16:47:50 +0000
Subject: [PATCH] Use implicit configuration object creation

The old way of using the configuration file was by instantiating a Config
object which read the file. This instance was passed to every function and
object that might need it.

The new way is by simply calling config.get('name') to get the configuration
value for 'name'. This lazily reads the configuration file and the contents
are cached for future calls.


git-svn-id: https://humgenprojects.lumc.nl/svn/mutalyzer/branches/implicit-config-branch@408 eb6bd6ab-9ccd-42b9-aceb-e2899b4a52f1
---
 bin/mutalyzer                    |   6 +-
 bin/mutalyzer-batchd             |  13 ++-
 bin/mutalyzer-cache-sync         |   8 +-
 bin/mutalyzer-mapping-update     |   6 +-
 bin/mutalyzer-webservice.wsgi    |   2 -
 extras/log-tools/find-crashes.py |   5 +-
 mutalyzer/Db.py                  |  35 +++-----
 mutalyzer/File.py                |  29 ++----
 mutalyzer/GenRecord.py           |  11 +--
 mutalyzer/Retriever.py           |  82 +++++------------
 mutalyzer/Scheduler.py           |  57 +++++-------
 mutalyzer/config.py              | 148 +++++++++++++++++--------------
 mutalyzer/mapping.py             |  22 ++---
 mutalyzer/mutator.py             |  31 +++----
 mutalyzer/output.py              |  29 +++---
 mutalyzer/parsers/genbank.py     |  12 +--
 mutalyzer/sync.py                |  12 +--
 mutalyzer/util.py                |  43 ++++++---
 mutalyzer/variantchecker.py      |  15 ++--
 mutalyzer/webservice.py          |  93 ++++++++++---------
 mutalyzer/website.py             |  70 +++++++--------
 tests/test_grammar.py            |   4 +-
 tests/test_mapping.py            |   6 +-
 tests/test_mutator.py            |   8 +-
 tests/test_variantchecker.py     |  76 +++++++---------
 tests/test_webservice.py         |   8 +-
 26 files changed, 352 insertions(+), 479 deletions(-)

diff --git a/bin/mutalyzer b/bin/mutalyzer
index 68345947..9013cd39 100755
--- a/bin/mutalyzer
+++ b/bin/mutalyzer
@@ -17,7 +17,6 @@ import os
 
 from mutalyzer import variantchecker
 from mutalyzer.output import Output
-from mutalyzer.config import Config
 from mutalyzer.util import format_usage
 
 
@@ -27,12 +26,11 @@ def main(cmd):
 
     @todo: documentation
     """
-    C = Config()
-    O = Output(__file__, C.Output)
+    O = Output(__file__)
 
     O.addMessage(__file__, -1, "INFO", "Received variant " + cmd)
 
-    RD = variantchecker.check_variant(cmd, C, O)
+    RD = variantchecker.check_variant(cmd, O)
 
     O.addMessage(__file__, -1, "INFO", "Finished processing variant " + cmd)
 
diff --git a/bin/mutalyzer-batchd b/bin/mutalyzer-batchd
index 868eafa9..2753d8a0 100755
--- a/bin/mutalyzer-batchd
+++ b/bin/mutalyzer-batchd
@@ -23,7 +23,7 @@ import signal
 import time
 import traceback
 
-from mutalyzer.config import Config
+from mutalyzer import config
 from mutalyzer.Db import Batch
 from mutalyzer.Scheduler import Scheduler
 
@@ -40,10 +40,7 @@ def daemonize():
     Write PID file when it is not locked and daemonize a loop processing
     scheduled batch jobs.
     """
-    config = Config()
-    batch_config = config.Batch
-
-    pidfile = os.path.realpath(batch_config.PIDfile)
+    pidfile = os.path.realpath(config.get('PIDfile'))
 
     lockfile = pidlockfile.TimeoutPIDLockFile(pidfile, acquire_timeout=1,
                                               threaded=False)
@@ -68,10 +65,10 @@ def daemonize():
 
     with context:
         # Note that any opened files are now closed. This is not a problem for
-        # the Config instance, since it does not read its file again after
+        # the config module, since it does not read its file again after
         # initialisation.
-        database = Batch(config.Db)
-        scheduler = Scheduler(config.Scheduler, database)
+        database = Batch()
+        scheduler = Scheduler(database)
 
         def stop_scheduler(signum, stack_frame):
             scheduler.stop()
diff --git a/bin/mutalyzer-cache-sync b/bin/mutalyzer-cache-sync
index 405084ea..5e012949 100755
--- a/bin/mutalyzer-cache-sync
+++ b/bin/mutalyzer-cache-sync
@@ -20,7 +20,6 @@ This program is intended to be run daily from cron. Example:
 
 import sys
 
-from mutalyzer.config import Config
 from mutalyzer.output import Output
 from mutalyzer.sync import CacheSync
 from mutalyzer import Db
@@ -31,11 +30,10 @@ def cache_sync(remote_wsdl, url_template, days):
     """
     Synchronize the database cache with other Mutalyzer instances.
     """
-    config = Config()
-    output = Output(__file__, config.Output)
-    database = Db.Cache(config.Db)
+    output = Output(__file__)
+    database = Db.Cache()
 
-    sync = CacheSync(config.Retriever, output, database)
+    sync = CacheSync(output, database)
     sync.sync_with_remote(remote_wsdl, url_template, days)
 
 
diff --git a/bin/mutalyzer-mapping-update b/bin/mutalyzer-mapping-update
index cbc88ef2..8fe6bb35 100755
--- a/bin/mutalyzer-mapping-update
+++ b/bin/mutalyzer-mapping-update
@@ -19,7 +19,6 @@ This program is intended to be run daily from cron. Example:
 
 import sys
 
-from mutalyzer.config import Config
 from mutalyzer.output import Output
 from mutalyzer.mapping import NCBIUpdater
 from mutalyzer.util import format_usage
@@ -39,12 +38,11 @@ def main(database, mapping_file, assembly):
 
     @todo: Also report how much was added/updated.
     """
-    config = Config()
-    output = Output(__file__, config.Output)
+    output = Output(__file__)
     output.addMessage(__file__, -1, 'INFO',
                       'Starting NCBI mapping data update')
 
-    updater = NCBIUpdater(database, config)
+    updater = NCBIUpdater(database)
     updater.load(mapping_file, assembly)
     updater.merge()
 
diff --git a/bin/mutalyzer-webservice.wsgi b/bin/mutalyzer-webservice.wsgi
index bc624da3..5a01545e 100755
--- a/bin/mutalyzer-webservice.wsgi
+++ b/bin/mutalyzer-webservice.wsgi
@@ -25,8 +25,6 @@ To start the built-in HTTP server on port 8081:
        kind of strictness checks on the input. For example, in
        transcriptInfo, the build argument must really be present. (Hint:
        use __checkBuild.)
-@todo: The mutalyzer.config.Config object can just be instantiated once
-       and we should not create it on every request.
 """
 
 
diff --git a/extras/log-tools/find-crashes.py b/extras/log-tools/find-crashes.py
index cea38c2e..0e6d791e 100755
--- a/extras/log-tools/find-crashes.py
+++ b/extras/log-tools/find-crashes.py
@@ -10,11 +10,10 @@ crashed.
 
 
 import os
-from mutalyzer.config import Config
+from mutalyzer import config
 
 
-config = Config()
-handle = open(config.Output.log, 'r')
+handle = open(config.get('log'), 'r')
 
 scanning = False
 line = handle.readline()
diff --git a/mutalyzer/Db.py b/mutalyzer/Db.py
index 5bd25f33..60d61a18 100644
--- a/mutalyzer/Db.py
+++ b/mutalyzer/Db.py
@@ -25,6 +25,7 @@ import warnings
 import MySQLdb
 
 from mutalyzer import util
+from mutalyzer import config
 
 
 #
@@ -115,7 +116,7 @@ class Mapping(Db) :
     Database functions for mapping of transcripts and genes.
 
     Special methods:
-        - __init__(build, config) ; Initialise the class.
+        - __init__(build) ; Initialise the class.
 
     Public methods:
         - get_protAcc(mrnaAcc)      ; Query the database for a protein ID.
@@ -135,18 +136,15 @@ class Mapping(Db) :
         - Mapping; Accumulated mapping info.
     """
 
-    def __init__(self, build, config) :
+    def __init__(self, build) :
         """
         Initialise the Db parent class. Use the local database for a certain
         build.
 
         @arg build: The version of the mapping database
         @type build: string
-        @arg config: Configuration variables
-        @type config: class instance
         """
-
-        Db.__init__(self, build, config.LocalMySQLuser, config.LocalMySQLhost)
+        Db.__init__(self, build, config.get('LocalMySQLuser'), config.get('LocalMySQLhost'))
     #__init__
 
     def get_NM_version(self, mrnaAcc) :
@@ -660,7 +658,7 @@ class Cache(Db) :
     Database functions for cache administration.
 
     Special methods:
-        - __init__(config) ; Initialise the class.
+        - __init__() ; Initialise the class.
 
     Public methods:
         - insertGB(accNo, GI, fileHash, ChrAccVer, ChrStart, ChrStop,
@@ -683,16 +681,12 @@ class Cache(Db) :
         - GBInfo ; Information about cached and uploaded GenBank files.
     """
 
-    def __init__(self, config) :
+    def __init__(self) :
         """
         Initialise the Db parent class. Use the internalDb.
-
-        @arg config: Configuration variables
-        @type config: class instance
         """
-
-        Db.__init__(self, config.internalDb, config.LocalMySQLuser,
-                    config.LocalMySQLhost)
+        Db.__init__(self, config.get('internalDb'),
+                    config.get('LocalMySQLuser'), config.get('LocalMySQLhost'))
     #__init__
 
     def insertGB(self, accNo, GI, fileHash, ChrAccVer, ChrStart,
@@ -1099,7 +1093,7 @@ class Batch(Db) :
     Database functions for the batch checker.
 
     Special methods:
-        - __init__(config) ; Initialise the class.
+        - __init__() ; Initialise the class.
 
     Public methods:
         - isJobListEmpty()     ; See if there are active jobs.
@@ -1121,16 +1115,13 @@ class Batch(Db) :
         - BatchQueue ; Requests.
     """
 
-    def __init__(self, config) :
+    def __init__(self) :
         """
         Initialise the Db parent class. Use the internalDb.
-
-        @arg config: Configuration variables
-        @type config: class instance
         """
-
-        Db.__init__(self, config.internalDb, config.LocalMySQLuser,
-                    config.LocalMySQLhost)
+        Db.__init__(self, config.get('internalDb'),
+                    config.get('LocalMySQLuser'),
+                    config.get('LocalMySQLhost'))
     #__init__
 
     def isJobListEmpty(self) :
diff --git a/mutalyzer/File.py b/mutalyzer/File.py
index a03a1b3a..561503d7 100644
--- a/mutalyzer/File.py
+++ b/mutalyzer/File.py
@@ -27,13 +27,14 @@ import types           # UnicodeType
 from cStringIO import StringIO
 
 from mutalyzer import util
+from mutalyzer import config
+
 
 class File() :
     """
     Parse CSV files and spreadsheets.
 
     Private variables:
-        - __config ; Configuration variables.
         - __output ; The Output object.
 
     Special methods:
@@ -53,21 +54,16 @@ class File() :
                                    and sanitize the output.
     """
 
-    def __init__(self, config, output) :
+    def __init__(self, output) :
         """
         Initialise the class.
 
         Private variables (altered):
-            - __config ; Initialised with configuration variables.
             - __output ; Set to the Output object.
 
-        @arg config: Configuration variables
-        @type config: class instance
         @arg output: Output object
         @type output: class instance
         """
-
-        self.__config = config
         self.__output = output #: The Output object
     #__init__
 
@@ -106,9 +102,6 @@ class File() :
         Parse a CSV file.
         The stream is not rewinded after use.
 
-        Private variables:
-            - __config ; The bufSize configuration variables.
-
         @arg handle: A handle to a stream
         @type handle: stream
 
@@ -167,7 +160,7 @@ class File() :
 
         # I don't think the .seek(0) is needed now we created a new handle
         new_handle.seek(0)
-        buf = new_handle.read(self.__config.bufSize)
+        buf = new_handle.read(config.get('bufSize'))
 
         # Default dialect
         dialect = 'excel'
@@ -270,9 +263,6 @@ class File() :
            - The first and the last element should be non-empty.
            - The first line should be the header defined in the config file.
 
-        Private variables:
-            - __config ; The header configuration variable.
-
         @todo: Add more new style old style logic
         @todo: if not inputl: try to make something out of it
 
@@ -289,7 +279,7 @@ class File() :
         jobl = [(l+1, row) for l, row in enumerate(job)]
 
         #TODO:  Add more new style old style logic
-        if jobl[0][1] == self.__config.header : #Old style NameCheckBatch job
+        if jobl[0][1] == config.get('header') : #Old style NameCheckBatch job
             ret = []
             notthree = []
             emptyfield = []
@@ -374,7 +364,7 @@ class File() :
         err = float(len(errlist))/len(ret)
         if err == 0:
             return (ret, columns)
-        elif err < self.__config.threshold:
+        elif err < config.get('threshold'):
             #allow a 5 (default) percent threshold for errors in batchfiles
             self.__output.addMessage(__file__, 3, "EBPARSE",
                     "There were errors in your batch entry file, they are "
@@ -391,19 +381,14 @@ class File() :
         Get the mime type of a stream by inspecting a fixed number of bytes.
         The stream is rewinded after use.
 
-        Private variables:
-            - __config: The bufSize configuration variables.
-
         @arg handle: A handle to a stream
         @type handle: stream
 
         @return: The mime type of a file
         @rtype: string
         """
-
         handle.seek(0)
-        buf = handle.read(self.__config.bufSize) #: The bufSize configuration variables.
-
+        buf = handle.read(config.get('bufSize')) #: The bufSize configuration variables.
 
         MagicInstance = magic.open(magic.MAGIC_MIME)
         MagicInstance.load()
diff --git a/mutalyzer/GenRecord.py b/mutalyzer/GenRecord.py
index 3c964872..90d50c0f 100644
--- a/mutalyzer/GenRecord.py
+++ b/mutalyzer/GenRecord.py
@@ -19,6 +19,7 @@ search for them each time.
 import Bio
 
 from mutalyzer import util
+from mutalyzer import config
 from mutalyzer import Crossmap
 from mutalyzer import Db
 
@@ -379,7 +380,7 @@ class GenRecord() :
         - checkRecord()   ;   Check and repair self.record.
     """
 
-    def __init__(self, output, config) :
+    def __init__(self, output) :
         """
         Initialise the class.
 
@@ -388,12 +389,8 @@ class GenRecord() :
 
         @arg output: an output object
         @type output: object
-        @arg config: a config object
-        @type config: object
         """
-
         self.__output = output
-        self.__config = config
         self.record = None
     #__init__
 
@@ -807,13 +804,13 @@ class GenRecord() :
         # TODO Also check a range properly.
         intronPos = abs(transcript.CM.g2x(position)[1])
         if intronPos :
-            if intronPos <= self.__config.spliceAlarm :
+            if intronPos <= config.get('spliceAlarm'):
                 self.__output.addMessage(__file__, 2, "WSPLICE",
                     "Mutation on splice site in gene %s transcript %s." % (
                     gene.name, transcript.name))
                 return
             #if
-            if intronPos <= self.__config.spliceWarn :
+            if intronPos <= config.get('spliceWarn'):
                 self.__output.addMessage(__file__, 2, "WSPLICE",
                     "Mutation near splice site in gene %s transcript %s." % (
                     gene.name, transcript.name))
diff --git a/mutalyzer/Retriever.py b/mutalyzer/Retriever.py
index ded70bcc..4f5f624c 100644
--- a/mutalyzer/Retriever.py
+++ b/mutalyzer/Retriever.py
@@ -24,6 +24,7 @@ from xml.dom import DOMException, minidom
 from xml.parsers import expat
 
 from mutalyzer import util
+from mutalyzer import config
 from mutalyzer.parsers import lrg
 from mutalyzer.parsers import genbank
 
@@ -32,17 +33,10 @@ class Retriever(object) :
     """
     Retrieve a record from either the cache or the NCBI.
 
-    Inherited variables from Db.Output.Config:
-        - email     ; The email address which we give to the NCBI.
-        - cache     ; The directory where the records are stored.
-        - cachesize ; Maximum size of the cache.
-
     Special methods:
-        - __init__(config, output, database) ; Use variables from the
+        - __init__(output, database) ; Use variables from the
         configuration file to initialise the class private variables.
 
-
-
     Private methods:
         - _foldersize(folder) ; Return the size of a folder.
         - _cleancache()       ; Keep the cache at a maximum size.
@@ -67,29 +61,21 @@ class Retriever(object) :
         - LogMsg(filename, message)     ; Log a message.
     """
 
-    def __init__(self, config, output, database) :
+    def __init__(self, output, database) :
         """
         Use variables from the configuration file for some simple
         settings. Make the cache directory if it does not exist yet.
 
-        Inherited variables from Db.Output.Config:
-            - email     ; The email address which we give to the NCBI.
-            - cache     ; The directory where the records are stored.
-
-        @arg config:
-        @type config:
         @arg output:
         @type output:
         @arg database:
         @type database:
         """
-
-        self._config = config
         self._output = output
         self._database = database
-        if not os.path.isdir(self._config.cache) :
-            os.mkdir(self._config.cache)
-        Entrez.email = self._config.email
+        if not os.path.isdir(config.get('cache')) :
+            os.mkdir(config.get('cache'))
+        Entrez.email = config.get('email')
         self.fileType = None
     #__init__
 
@@ -119,18 +105,13 @@ class Retriever(object) :
         First, the cache checked for its size, if it exceeds the maximum
         size the ``oldest'' files are deleted. Note that accessing a file
         makes it ``new''.
-
-        Inherited variables from Db.Output.Config:
-            - cache     ; Directory under scrutiny.
-            - cachesize ; Maximum size of the cache.
         """
-
-        if self._foldersize(self._config.cache) < self._config.cachesize:
+        if self._foldersize(config.get('cache')) < config.get('cachesize'):
             return
 
         # Build a list of files sorted by access time.
         cachelist = []
-        for (path, dirs, files) in os.walk(self._config.cache) :
+        for (path, dirs, files) in os.walk(config.get('cache')) :
             for filename in files :
                 filepath = os.path.join(path, filename)
                 cachelist.append(
@@ -141,7 +122,7 @@ class Retriever(object) :
         # small enough (or until the list is exhausted).
         for i in range(0, len(cachelist)) :
             os.remove(cachelist[i][1])
-            if self._foldersize(self._config.cache) < self._config.cachesize:
+            if self._foldersize(config.get('cache')) < config.get('cachesize'):
                 break;
         #for
     #_cleancache
@@ -150,17 +131,13 @@ class Retriever(object) :
         """
         Convert an accession number to a filename.
 
-        Inherited variables from Db.Output.Config:
-            - cache     ; Name of the cache directory.
-
         @arg name: The accession number
         @type name: string
 
         @return: A filename
         @rtype: string
         """
-
-        return self._config.cache + '/' + name + "." + self.fileType + ".bz2"
+        return config.get('cache') + '/' + name + "." + self.fileType + ".bz2"
     #_nametofile
 
     def _write(self, raw_data, filename) :
@@ -339,13 +316,12 @@ class GenBankRetriever(Retriever):
     """
     """
 
-    def __init__(self, config, output, database):
-        # TODO documentation
+    def __init__(self, output, database):
         """
+        @todo: Documentation.
         """
-
         # Recall init of parent
-        Retriever.__init__(self, config, output, database)
+        Retriever.__init__(self, output, database)
         self.fileType = "gb"
         # Child specific init
     #__init__
@@ -466,9 +442,6 @@ class GenBankRetriever(Retriever):
         The content of the slice is placed in the cache with the UD number
         as filename.
 
-        Inherited variables from Db.Output.Config:
-            - maxDldSize ; Maximum size of the slice.
-
         @arg accno: The accession number of the chromosome
         @type accno: string
         @arg start: Start position of the slice
@@ -490,7 +463,7 @@ class GenBankRetriever(Retriever):
             return None
 
         # The slice can not be too big.
-        if stop - start > self._config.maxDldSize :
+        if stop - start > config.get('maxDldSize'):
             return None
 
         # Check whether we have seen this slice before.
@@ -610,23 +583,18 @@ class GenBankRetriever(Retriever):
         If the downloaded file is recognised by its hash, the old UD number
         is used.
 
-        Inherited variables from Db.Output.Config:
-            - maxDldSize ; Maximum size of the file.
-            - minDldSize ; Minimum size of the file.
-
         @arg url: Location of a GenBank record
         @type url: string
 
         @return: UD or None
         @rtype: string
         """
-
         handle = urllib2.urlopen(url)
         info = handle.info()
         if info["Content-Type"] == "text/plain" :
             length = int(info["Content-Length"])
-            if length > self._config.minDldSize and \
-               length < self._config.maxDldSize :
+            if length > config.get('minDldSize') and \
+               length < config.get('maxDldSize'):
                 raw_data = handle.read()
                 md5sum = self._calcHash(raw_data)
                 UD = self._database.getGBFromHash(md5sum)
@@ -756,22 +724,19 @@ class LRGRetriever(Retriever):
                                    the cache and return the record.
     """
 
-    def __init__(self, config, output, database):
+    def __init__(self, output, database):
         #TODO documentation
         """
         Initialize the class.
 
         @todo: documentation
-        @arg  config:
-        @type  config:
         @arg  output:
         @type  output:
         @arg  database:
         @type  database:
         """
-
         # Recall init of parent
-        Retriever.__init__(self, config, output, database)
+        Retriever.__init__(self, output, database)
         self.fileType = "xml"
         # Child specific init
     #__init__
@@ -815,9 +780,6 @@ class LRGRetriever(Retriever):
         grab the file from the confirmed section, if this fails, get it
         from the pending section.
 
-        Inherited variables from Config.Retriever
-            - lrgURL  ; The base url from where LRG files are fetched
-
         @arg name: The name of the LRG file to fetch
         @type name: string
 
@@ -825,7 +787,7 @@ class LRGRetriever(Retriever):
         @rtype: string
         """
 
-        prefix = self._config.lrgURL
+        prefix = config.get('lrgURL')
         url        = prefix + "%s.xml"          % name
         pendingurl = prefix + "pending/%s.xml"  % name
 
@@ -849,10 +811,6 @@ class LRGRetriever(Retriever):
         """
         Download an LRG record from an URL.
 
-        Inherited variables from Db.Output.Config:
-            - maxDldSize  ; Maximum size of the file.
-            - minDldSize  ; Minimum size of the file.
-
         @arg url: Location of the LRG record
         @type url: string
 
@@ -872,7 +830,7 @@ class LRGRetriever(Retriever):
         if info["Content-Type"] == "application/xml" and info.has_key("Content-length"):
 
             length = int(info["Content-Length"])
-            if self._config.minDldSize < length < self._config.maxDldSize:
+            if config.get('minDldSize') < length < config.get('maxDldSize'):
                 raw_data = handle.read()
                 handle.close()
 
diff --git a/mutalyzer/Scheduler.py b/mutalyzer/Scheduler.py
index cc10261d..ca30875f 100644
--- a/mutalyzer/Scheduler.py
+++ b/mutalyzer/Scheduler.py
@@ -20,9 +20,9 @@ import smtplib                          # smtplib.STMP
 from email.mime.text import MIMEText    # MIMEText
 
 import mutalyzer
+from mutalyzer import config
 from mutalyzer import variantchecker
 from mutalyzer.grammar import Grammar
-from mutalyzer.config import Config
 from mutalyzer.output import Output
 from mutalyzer.mapping import Converter
 from mutalyzer import Retriever           # Retriever.Retriever
@@ -34,7 +34,7 @@ __all__ = ["Scheduler"]
 class Scheduler() :
     """
     Special methods:
-        - __init__(config, database) ;
+        - __init__(database) ;
 
     Public methods:
         - addJob(outputFilter, eMail, queue, fromHost, jobType, Arg1) ; Add a
@@ -47,21 +47,16 @@ class Scheduler() :
         - Batch Position Converter
     """
 
-    def __init__(self, config, database) :
+    def __init__(self, database) :
         #TODO: documentation
         """
-        Initialize the Scheduler, which requires a config object
-        and a database connection.
+        Initialize the Scheduler, which requires a database connection.
 
         @todo: documentation
 
-        @arg config: Config object
-        @type config: object
         @arg database:
         @type database:
         """
-
-        self.__config = config
         self.__database = database
         self.__run = True
     #__init__
@@ -89,10 +84,6 @@ class Scheduler() :
         """
         Send an e-mail containing an url to a batch job submitter.
 
-        Private variables:
-            - __config ; The variables mailSubject and mailFrom
-                       are used.
-
         @todo: Handle Connection errors in a try, except clause
 
         @arg mailTo: The batch job submitter
@@ -127,13 +118,13 @@ Thanks for using Mutalyzer.
 With kind regards,
 Mutalyzer batch checker.""" % url)
 
-        message["Subject"] = self.__config.mailSubject
-        message["From"] = self.__config.mailFrom
+        message["Subject"] = config.get('mailSubject')
+        message["From"] = config.get('mailFrom')
         message["To"] = mailTo
 
         smtpInstance = smtplib.SMTP()
         smtpInstance.connect()
-        smtpInstance.sendmail(self.__config.mailFrom, mailTo,
+        smtpInstance.sendmail(config.get('mailFrom'), mailTo,
                               message.as_string())
         smtpInstance.quit()
     #__sendMail
@@ -364,9 +355,7 @@ Mutalyzer batch checker.""" % url)
         @arg flags: Flags of the current entry
         @type flags:
         """
-
-        C = Config()
-        O = Output(__file__, C.Output)
+        O = Output(__file__)
         O.addMessage(__file__, -1, "INFO",
             "Received NameChecker batchvariant " + cmd)
 
@@ -398,12 +387,12 @@ Mutalyzer batch checker.""" % url)
             outputline += batchOutput[0]
 
         #Output
-        filename = "%s/Results_%s.txt" % (self.__config.resultsDir, i)
+        filename = "%s/Results_%s.txt" % (config.get('resultsDir'), i)
         if not os.path.exists(filename) :
             # If the file does not yet exist, create it with the correct
             # header above it. The header is read from the config file as
             # a list. We need a tab delimited string.
-            header = self.__config.nameCheckOutHeader
+            header = config.get('nameCheckOutHeader')
             handle = open(filename, 'a')
             handle.write("%s\n" % "\t".join(header))
         #if
@@ -436,9 +425,7 @@ Mutalyzer batch checker.""" % url)
         @arg flags: Flags of the current entry
         @type flags:
         """
-
-        C = Config()
-        output = Output(__file__, C.Output)
+        output = Output(__file__)
         grammar = Grammar(output)
 
         output.addMessage(__file__, -1, "INFO",
@@ -457,12 +444,12 @@ Mutalyzer batch checker.""" % url)
             result = "|".join(output.getBatchMessages(3))
 
         #Output
-        filename = "%s/Results_%s.txt" % (self.__config.resultsDir, i)
+        filename = "%s/Results_%s.txt" % (config.get('resultsDir'), i)
         if not os.path.exists(filename) :
             # If the file does not yet exist, create it with the correct
             # header above it. The header is read from the config file as
             # a list. We need a tab delimited string.
-            header = self.__config.syntaxCheckOutHeader
+            header = config.get('syntaxCheckOutHeader')
             handle = open(filename, 'a')
             handle.write("%s\n" % "\t".join(header))
         #if
@@ -499,9 +486,7 @@ Mutalyzer batch checker.""" % url)
         @arg flags: Flags of the current entry
         @type flags:
         """
-
-        C = Config()
-        O = Output(__file__, C.Output)
+        O = Output(__file__)
         variant = cmd
         variants = None
         gName = ""
@@ -559,12 +544,12 @@ Mutalyzer batch checker.""" % url)
         error = "%s" % "|".join(O.getBatchMessages(3))
 
         #Output
-        filename = "%s/Results_%s.txt" % (self.__config.resultsDir, i)
+        filename = "%s/Results_%s.txt" % (config.get('resultsDir'), i)
         if not os.path.exists(filename) :
             # If the file does not yet exist, create it with the correct
             # header above it. The header is read from the config file as
             # a list. We need a tab delimited string.
-            header = self.__config.positionConverterOutHeader
+            header = config.get('positionConverterOutHeader')
             handle = open(filename, 'a')
             handle.write("%s\n" % "\t".join(header))
         #if
@@ -598,9 +583,7 @@ Mutalyzer batch checker.""" % url)
         @arg flags: Flags of the current entry
         @type flags:
         """
-
-        C = Config()
-        O = Output(__file__, C.Output)
+        O = Output(__file__)
         O.addMessage(__file__, -1, "INFO",
             "Received SNP converter batch rs" + cmd)
 
@@ -610,7 +593,7 @@ Mutalyzer batch checker.""" % url)
 
         descriptions = []
         if not skip :
-            R = Retriever.Retriever(C.Retriever, O, None)
+            R = Retriever.Retriever(O, None)
             descriptions = R.snpConvert(cmd)
 
         # Todo: Is output ok?
@@ -619,12 +602,12 @@ Mutalyzer batch checker.""" % url)
         outputline += "%s\t" % "|".join(O.getBatchMessages(3))
 
         #Output
-        filename = "%s/Results_%s.txt" % (self.__config.resultsDir, i)
+        filename = "%s/Results_%s.txt" % (config.get('resultsDir'), i)
         if not os.path.exists(filename) :
             # If the file does not yet exist, create it with the correct
             # header above it. The header is read from the config file as
             # a list. We need a tab delimited string.
-            header = self.__config.snpConverterOutHeader
+            header = config.get('snpConverterOutHeader')
             handle = open(filename, 'a')
             handle.write("%s\n" % "\t".join(header))
         #if
diff --git a/mutalyzer/config.py b/mutalyzer/config.py
index cb98f726..ae7f8cb0 100644
--- a/mutalyzer/config.py
+++ b/mutalyzer/config.py
@@ -1,13 +1,26 @@
 """
-Module for reading the config file and splitting up the variables into
-subclasses. Each of these subclasses are used to configure a specific
-module.
+Module for reading the configuration values from configuration files.
+
+All communication with this module should be done by using the get function
+which returns a configuration value, given a name.
+
+Reading the configuration file is implemented lazily and as such done upon the
+first call to the get function.
+
+Configuration values are read from two locations, in this order:
+1) /etc/mutalyzer/config
+2) $XDG_CONFIG_HOME/mutalyzer/config
+
+If both files exist, values defined in the second overwrite values defined in
+the first.
 """
 
 
 import os
 from configobj import ConfigObj
 
+from mutalyzer.util import singleton
+
 
 SYSTEM_CONFIGURATION = '/etc/mutalyzer/config'
 USER_CONFIGURATION = os.path.join(
@@ -17,22 +30,36 @@ USER_CONFIGURATION = os.path.join(
 
 
 class ConfigurationError(Exception):
+    """
+    Raised when a configuration file cannot be read.
+    """
     pass
 
 
-class Config():
+def get(name):
+    """
+    Get a configuration value by name.
+
+    @arg name: Name for the configuration value.
+    @type name: string
+
+    @raise ConfigurationError: If configuration value could not be read.
+        Reasons are:
+        - Configuration file could not be parsed.
+        - Not all variables are present in configuration file.
+        - Given configuration value name does not exist.
     """
-    Read the configuration file and store the data in subclasses.
+    return _Config().get(name)
+
+
+@singleton
+class _Config():
     """
-    class Retriever(): pass
-    class Db(): pass
-    class Output(): pass
-    class Mutator(): pass
-    class Scheduler(): pass
-    class Batch(): pass
-    class File(): pass
-    class GenRecord(): pass
+    Read the configuration file and provide access to its values.
 
+    Please note the limitations from the use of the @singleton decorator as
+    described in its docstring.
+    """
     def __init__(self, filename=None):
         """
         Initialise the class with variables read from the configuration
@@ -51,10 +78,6 @@ class Config():
         is set. In that case, the locations listed above are ignored and the
         configuration is read from {filename}.
 
-        By the DRY-principle, we don't enumerate the configuration variables
-        for each class in documentation. Instead, what variables are used by
-        each class is easy to see from the code below.
-
         @kwarg filename: Optional filename to read configuration from. If
             present, this overrides automatic detection of configuration file
             location.
@@ -85,58 +108,53 @@ class Config():
 
         try:
 
-            # Set the variables needed by the Retriever module.
-            self.Retriever.email = config["email"]
-            self.Retriever.cache = config["cache"]
-            self.Retriever.cachesize = int(config["cachesize"]) * 1048576
-            self.Retriever.maxDldSize = int(config["maxDldSize"]) * 1048576
-            self.Retriever.minDldSize = int(config["minDldSize"])
-            self.Retriever.lrgURL = config["lrgurl"]
-
-            # Set the variables needed by the Db module.
-            self.Db.internalDb = config["internalDb"]
-            self.Db.dbNames = config["dbNames"]
-            self.Db.LocalMySQLuser = config["LocalMySQLuser"]
-            self.Db.LocalMySQLhost = config["LocalMySQLhost"]
-
-            # Set the variables needed by the Output module.
-            self.Output.log = config["log"]
-            self.Output.datestring = config["datestring"]
-            self.Output.loglevel = int(config["loglevel"])
-            self.Output.outputlevel = int(config["outputlevel"])
-            self.Output.debug = config.as_bool('debug')
-
-            # Set the variables needed by the Mutator module.
-            self.Mutator.flanksize = int(config["flanksize"])
-            self.Mutator.maxvissize = int(config["maxvissize"])
-            self.Mutator.flankclipsize = int(config["flankclipsize"])
-
-            # Set the variables needed by the Scheduler module.
-            self.Scheduler.mailFrom = config["mailFrom"]
-            self.Scheduler.mailSubject = config["mailSubject"]
-            self.Scheduler.resultsDir = config["resultsDir"]
-            self.Scheduler.nameCheckOutHeader = config["nameCheckOutHeader"]
-            self.Scheduler.syntaxCheckOutHeader = config["syntaxCheckOutHeader"]
-            self.Scheduler.positionConverterOutHeader = config["positionConverterOutHeader"]
-            self.Scheduler.snpConverterOutHeader = config["snpConverterOutHeader"]
-
-            # Set thte variables neede for the Batch module.
-            self.Batch.PIDfile = config["PIDfile"]
-            self.Batch.batchInputMaxSize = int(config["batchInputMaxSize"]) * 1048576
-
-            # Set the variables needed by the File module.
-            self.File.bufSize = int(config["bufSize"])
-            self.File.header = config["header"]
-            self.File.threshold = float(config["threshold"])
-
-            # Set the variables needed by the File module.
-            self.GenRecord.spliceAlarm = int(config["spliceAlarm"])
-            self.GenRecord.spliceWarn = int(config["spliceWarn"])
+            # We explicitely read all configuration values ad store them in
+            # our own dictionary. This makes sure we notice missing or
+            # incorrect values upon instantiation.
+
+            # A few 'special' values.
+            self._values = {'debug':     config.as_bool('debug'),
+                            'threshold': float(config['threshold'])}
+
+            # Simple string values.
+            for name in ('email', 'cache', 'lrgurl', 'internalDb', 'dbNames',
+                         'LocalMySQLuser', 'LocalMySQLhost', 'log',
+                         'datestring', 'mailFrom', 'mailSubject',
+                         'resultsDir', 'nameCheckOutHeader',
+                         'syntaxCheckOutHeader', 'positionConverterOutHeader',
+                         'snpConverterOutHeader', 'PIDfile', 'header'):
+                self._values[name] = config[name]
+
+            # Simple integer values.
+            for name in ('minDldSize', 'loglevel', 'outputlevel', 'flanksize',
+                         'maxvissize', 'flankclipsize', 'bufSize',
+                         'spliceAlarm', 'spliceWarn'):
+                self._values[name] = int(config[name])
+
+            # File sizes (given in megabytes, stored in bytes).
+            for name in ('cachesize', 'maxDldSize', 'batchInputMaxSize'):
+                self._values[name] = int(config[name]) * 1048576
 
         except KeyError as e:
             raise ConfigurationError('Missing configuration value: %s' % e)
     #__init__
 
+    def get(self, name):
+        """
+        Get a configuration value by name.
+
+        @arg name: Name for the configuration value.
+        @type name: string
+
+        @raise ConfigurationError: If given configuration value name does not
+            exist.
+        """
+        try:
+            return self._values[name]
+        except KeyError:
+            raise ConfigurationError('No such configuration value: %s' % name)
+    #get
+
     def _load_config(self, filename):
         """
         Create a ConfigObj from the configuration in {filename}.
@@ -150,4 +168,4 @@ class Config():
             raise ConfigurationError('Could not parse configuration file: %s' \
                                      % filename)
     #_load_config
-#Config
+#_Config
diff --git a/mutalyzer/mapping.py b/mutalyzer/mapping.py
index 28dc5406..584541f5 100644
--- a/mutalyzer/mapping.py
+++ b/mutalyzer/mapping.py
@@ -41,22 +41,19 @@ class Converter(object) :
     @todo: Refactor anything using {mutalyzer.models} into the {webservice}
     module.
     """
-    def __init__(self, build, C, O) :
+    def __init__(self, build, O) :
         """
         Initialise the class.
 
         @arg build: the genome build version of the organism (e.g. hg19 for
         human genome build version 19)
         @type build: string
-        @arg C: crossmapper object
-        @type C: object
         @arg O: output object
         @type O: object
         """
         self.build = None
         self.__output = O
-        self.__config = C
-        self.__database = Db.Mapping(build, C.Db)
+        self.__database = Db.Mapping(build)
 
         # Populated arguments
         self.parseTree = None
@@ -609,17 +606,14 @@ class Updater(object):
     information into the 'MappingTemp' table. The {merge} method merges this
     table into the real 'Mapping' table.
     """
-    def __init__(self, build, config):
+    def __init__(self, build):
         """
         @arg build: Human genome build (or database name), i.e. 'hg18' or
             'hg19'.
         @type build: string
-        @arg config: A configuration object.
-        @type config: mutalyzer.config.Config
         """
         self.build = build
-        self.config = config
-        self.db = Db.Mapping(build, config.Db)
+        self.db = Db.Mapping(build)
     #__init__
 
     def load(self, *args, **kwargs):
@@ -649,7 +643,7 @@ class NCBIUpdater(Updater):
 
     Example usage:
 
-        >>> updater = NCBIUpdater('hg19', mutalyzer.config.Config())
+        >>> updater = NCBIUpdater('hg19')
         >>> updater.load('/tmp/seq_gene.md', 'GRCh37.p2-Primary Assembly')
         >>> updater.merge()
 
@@ -659,16 +653,14 @@ class NCBIUpdater(Updater):
                'feature_name', 'feature_id', 'feature_type', 'group_label',
                'transcript', 'evidence_code']
 
-    def __init__(self, build, config):
+    def __init__(self, build):
         """
         @arg build: Human genome build (or database name), i.e. 'hg18' or
             'hg19'.
         @type build: string
-        @arg config: A configuration object.
-        @type config: mutalyzer.config.Config
         """
         self.exon_backlog = {}
-        super(NCBIUpdater, self).__init__(build, config)
+        super(NCBIUpdater, self).__init__(build)
     #__init__
 
     def load(self, mapping_file, assembly):
diff --git a/mutalyzer/mutator.py b/mutalyzer/mutator.py
index 90652050..2a59c8b7 100644
--- a/mutalyzer/mutator.py
+++ b/mutalyzer/mutator.py
@@ -12,12 +12,14 @@ The original as well as the mutated string are stored here.
 """
 
 
-from mutalyzer import util
 from Bio import Restriction
 from Bio.Seq import Seq
 from Bio.Alphabet.IUPAC import IUPACAmbiguousDNA
 from Bio.Seq import reverse_complement
 
+from mutalyzer import util
+from mutalyzer import config
+
 
 class Mutator() :
     """
@@ -28,7 +30,6 @@ class Mutator() :
     'addedRestrictionSites' respectively.
 
     Private variables:
-        - __config           ; Configuration variables of this class.
         - __output           ; The output object.
         - __shift            ; A sorted list of tuples (position, shiftsize)
                                where the modifications in length are stored.
@@ -72,13 +73,11 @@ class Mutator() :
                                      position pos1 to pos2.
     """
 
-    def __init__(self, orig, config, output) :
+    def __init__(self, orig, output) :
         """
         Initialise the class with the original string.
 
         Private variables (altered):
-            - __config           ; Initialised with the configuration
-                                   variables.
             - __output           ; Initialised with the output object.
             - __shift            ; Initialised to the empty list.
             - __restrictionBatch ; Initialised to a default set of
@@ -90,13 +89,9 @@ class Mutator() :
 
         @arg orig:   The original string before mutation
         @type orig: string
-        @arg config: Configuration variables
-        @type config: object
         @arg output: The output object
         @type output: object
         """
-
-        self.__config = config
         self.__output = output
         self.__shift = []
         self.__removed_sites = set()
@@ -214,8 +209,6 @@ class Mutator() :
         we perform the alteration.
 
         Private variables:
-            - __config ; The variables maxvissize, flanksize and flankclipsize
-                         are used in the visualisation.
             - __output ; Visualisation information is added.
 
         Public variables (altered):
@@ -237,8 +230,8 @@ class Mutator() :
         # This part is for visualisation.
         #
 
-        loflank = self.orig[max(pos1 - self.__config.flanksize, 0):pos1]
-        roflank = self.orig[pos2:pos2 + self.__config.flanksize]
+        loflank = self.orig[max(pos1 - config.get('flanksize'), 0):pos1]
+        roflank = self.orig[pos2:pos2 + config.get('flanksize')]
         delPart = self.orig[pos1:pos2]
         #odel = delPart
         #if len(odel) > self.__config.maxvissize :
@@ -249,8 +242,8 @@ class Mutator() :
 
         bp1 = self.shiftpos(pos1)
         bp2 = self.shiftpos(pos2)
-        lmflank = self.mutated[max(bp1 - self.__config.flanksize, 0):bp1]
-        rmflank = self.mutated[bp2:bp2 + self.__config.flanksize]
+        lmflank = self.mutated[max(bp1 - config.get('flanksize'), 0):bp1]
+        rmflank = self.mutated[bp2:bp2 + config.get('flanksize')]
 
         #insvis = ins
         #if len(ins) > self.__config.maxvissize :
@@ -304,10 +297,10 @@ class Mutator() :
         @rtype:  string
         """
 
-        if len(string) > self.__config.maxvissize :
-            return "%s [%ibp] %s" % (string[:self.__config.flankclipsize],
-                len(string) - self.__config.flankclipsize * 2,
-                string[-self.__config.flankclipsize:])
+        if len(string) > config.get('maxvissize'):
+            return "%s [%ibp] %s" % (string[:config.get('flankclipsize')],
+                len(string) - config.get('flankclipsize') * 2,
+                string[-config.get('flankclipsize'):])
         return string
     #visualiseIns
 
diff --git a/mutalyzer/output.py b/mutalyzer/output.py
index 53bedeed..04d552b1 100644
--- a/mutalyzer/output.py
+++ b/mutalyzer/output.py
@@ -26,6 +26,7 @@ Public classes:
 import time
 
 from mutalyzer import util
+from mutalyzer import config
 from mutalyzer.models import SoapMessage
 
 
@@ -34,7 +35,6 @@ class Output() :
     Provide an output interface for errors, warnings and logging purposes.
 
     Private variables:
-        - __config     ; Configuration variables.
         - __outputdata ; The output dictionary.
         - __messages   ; The messages list.
         - __instance   ; The name of the module that made this object.
@@ -43,10 +43,9 @@ class Output() :
         - __warnings   ; The number of warnings that have been processed.
 
     Special methods:
-        - __init__(instance, config) ; Initialise the class with variables
-                                       from the config file and the calling
-                                       module.
-        - __del__()                  ; Close the logfile and clean up.
+        - __init__(instance) ; Initialise the class with the calling
+                               module.
+        - __del__()          ; Close the logfile and clean up.
 
     Public methods:
         - addMessage(filename, level, code, description) ; Add a message to
@@ -59,13 +58,11 @@ class Output() :
                                     and warnings.
     """
 
-    def __init__(self, instance, config) :
+    def __init__(self, instance):
         """
-        Initialise the class private variables with variables from the
-        config file and the calling module.
+        Initialise the class with the calling module.
 
         Private variables (altered):
-            - __config     ; Configuration variables.
             - __outputdata ; The output dictionary.
             - __messages   ; The messages list.
             - __instance   ; Initialised with the name of the module that
@@ -77,15 +74,11 @@ class Output() :
 
         @arg instance: The filename of the module that created this object
         @type instance: string
-        @arg config: The configuration object
-        @type config: object
         """
-
-        self.__config = config
         self.__outputData = {}
         self.__messages = []
         self.__instance = util.nice_filename(instance)
-        self.__loghandle = open(self.__config.log, "a+")
+        self.__loghandle = open(config.get('log'), "a+")
         self.__errors = 0
         self.__warnings = 0
     #__init__
@@ -120,7 +113,6 @@ class Output() :
         Private variables:
             - __messages  ; The messages list.
             - __instance  ; Module that created the Output object.
-            - __config    ; The variables loglevel and datestring are used.
             - __loghandle ; Handle to the log file.
 
         Private variables (altered):
@@ -145,9 +137,9 @@ class Output() :
 
         # Log the message if the message is important enough, or if it is only
         # meant to be logged (level -1).
-        if level >= self.__config.loglevel or level == -1 :
+        if level >= config.get('loglevel') or level == -1 :
             self.__loghandle.write(time.strftime(
-                self.__config.datestring + ' ') + "%s (%s) %s: %s: %s\n" % (
+                config.get('datestring') + ' ') + "%s (%s) %s: %s: %s\n" % (
                     self.__instance, nice_name, code, message.named_level(),
                     description))
             self.__loghandle.flush()
@@ -160,12 +152,11 @@ class Output() :
 
         Private variables:
             - __messages  ; The messages list.
-            - __config    ; The variable outputlevel is used.
 
         @return: A list of messages
         @rtype: list
         """
-        return filter(lambda m: m.level >= self.__config.outputlevel,
+        return filter(lambda m: m.level >= config.get('outputlevel'),
                       self.__messages)
     #getMessages
 
diff --git a/mutalyzer/parsers/genbank.py b/mutalyzer/parsers/genbank.py
index 060e9a52..8f640f61 100644
--- a/mutalyzer/parsers/genbank.py
+++ b/mutalyzer/parsers/genbank.py
@@ -8,7 +8,7 @@ import bz2
 from Bio import SeqIO, Entrez
 from Bio.Alphabet import ProteinAlphabet
 
-from mutalyzer.config import Config
+from mutalyzer import config
 from mutalyzer import Db
 from mutalyzer.GenRecord import PList, Locus, Gene, Record, GenRecord
 
@@ -52,17 +52,11 @@ class GBparser():
         """
         Initialise the class
 
-        Public variables:
-            - config ; Config object.
-
         Private variables:
             - __database ; Db.Cache object
-
-        @requires: Config
         """
-        config = Config()
-        Entrez.email = config.Retriever.email
-        self.__database = Db.Cache(config.Db)
+        Entrez.email = config.get('email')
+        self.__database = Db.Cache()
     #__init__
 
     def __location2pos(self, location):
diff --git a/mutalyzer/sync.py b/mutalyzer/sync.py
index 2a96446b..ae3622b3 100644
--- a/mutalyzer/sync.py
+++ b/mutalyzer/sync.py
@@ -11,6 +11,7 @@ from datetime import datetime, timedelta
 import urllib2
 from suds.client import Client
 
+from mutalyzer import config
 from mutalyzer import Retriever
 
 
@@ -21,18 +22,15 @@ class CacheSync(object):
     """
     Synchronize the database cache with other Mutalyzer instances.
     """
-    def __init__(self, config, output, database):
+    def __init__(self, output, database):
         """
         Instantiate the object.
 
-        @arg config: A configuration object.
-        @type config: mutalyzer.config.Config.Retriever
         @arg output: An output object.
         @type output: mutalyzer.output.Output
         @arg database: A database object.
         @type database: mutalyzer.Db.Cache
         """
-        self._config = config
         self._output = output
         self._database = database
 
@@ -60,7 +58,7 @@ class CacheSync(object):
         for entry in entries:
             # Note that this way we only include Genbank files, not LRG files.
             cached = None
-            if os.path.isfile(os.path.join(self._config.cache,
+            if os.path.isfile(os.path.join(config.get('cache'),
                                            '%s.gb.bz2' % entry[0])):
                 cached = '%s.gb' % entry[0]
             cache.append({'name':                  entry[0],
@@ -135,9 +133,7 @@ class CacheSync(object):
         handle.close()
 
         # Store remote data
-        retriever = Retriever.GenBankRetriever(self._config,
-                                               self._output,
-                                               self._database)
+        retriever = Retriever.GenBankRetriever(self._output, self.database)
         retriever.write(data, name, 0)
 
     def sync_with_remote(self, remote_wsdl, url_template,
diff --git a/mutalyzer/util.py b/mutalyzer/util.py
index 0918d4c2..8738bbca 100644
--- a/mutalyzer/util.py
+++ b/mutalyzer/util.py
@@ -1,20 +1,20 @@
 """
 General utility functions.
 
-@todo: All these functions come from the old Mutalyzer.py file. Try to find
-       general utility functions in other modules too.
+@todo: Most of these functions come from the old Mutalyzer.py file. Try to
+    find general utility functions in other modules too.
 @todo: Use exceptions for failure handling.
 @todo: End vs stop. I guess we should use start/stop (end goes with beginning).
-       Or first/last, or acceptor/donor. Anyway, CDS is always denoted with
-       start/stop. Important thing is that the semantics should be clear.
-       Idea:
-       * CDS -> use start/stop
-       * splice sites or exons -> acceptor/donor
-       * translation -> begin/end
-       * any range of bases -> first/last
-       * interbase position (if two numbers are used) -> before/after
+    Or first/last, or acceptor/donor. Anyway, CDS is always denoted with
+    start/stop. Important thing is that the semantics should be clear.
+    Idea:
+    * CDS -> use start/stop
+    * splice sites or exons -> acceptor/donor
+    * translation -> begin/end
+    * any range of bases -> first/last
+    * interbase position (if two numbers are used) -> before/after
 @todo: We can also group this in separate files in a util/ directory, according
-       to function (e.g. util/sequences.py, util/positioning.py, etc).
+    to function (e.g. util/sequences.py, util/positioning.py, etc).
 @todo: Unit tests (some can directly be extracted from the docstring).
 """
 
@@ -788,6 +788,27 @@ def skip(f):
 #skip
 
 
+def singleton(cls):
+    """
+    Decorator to define a class with a singleton instance.
+
+    Note that this decorator makes cls a function instead of a class and
+    things like super() and classmethods won't work anymore. So be carefull
+    with this and certainly don't use it with subclassing.
+
+    By Shane Hathaway, taken from PEP318 [1].
+
+    [1] http://www.python.org/dev/peps/pep-0318/#examples
+    """
+    instances = {}
+    def getinstance():
+        if cls not in instances:
+            instances[cls] = cls()
+        return instances[cls]
+    return getinstance
+#singleton
+
+
 def monkey_patch_suds():
     """
     Apply our monkey-patch for the suds package.
diff --git a/mutalyzer/variantchecker.py b/mutalyzer/variantchecker.py
index 8b7eb9e7..7ece5cbe 100644
--- a/mutalyzer/variantchecker.py
+++ b/mutalyzer/variantchecker.py
@@ -1432,7 +1432,7 @@ def process_variant(mutator, description, record, output):
 #process_variant
 
 
-def check_variant(description, config, output):
+def check_variant(description, output):
     """
     Check the variant described by {description} according to the HGVS variant
     nomenclature and populate the {output} object with various information
@@ -1440,8 +1440,6 @@ def check_variant(description, config, output):
 
     @arg description: Variant description in HGVS notation.
     @type description: string
-    @arg config: A configuration object.
-    @type config: Modules.Config.Config
     @arg output: An output object.
     @type output: Modules.Output.Output
 
@@ -1471,12 +1469,12 @@ def check_variant(description, config, output):
 
     gene_symbol = transcript_id = ''
 
-    database = Db.Cache(config.Db)
+    database = Db.Cache()
     if parsed_description.LrgAcc:
         filetype = 'LRG'
         record_id = parsed_description.LrgAcc
         transcript_id = parsed_description.LRGTranscriptID
-        retriever = Retriever.LRGRetriever(config.Retriever, output, database)
+        retriever = Retriever.LRGRetriever(output, database)
     else:
         filetype = 'GB'
         if parsed_description.Gene:
@@ -1485,8 +1483,7 @@ def check_variant(description, config, output):
             if parsed_description.Gene.ProtIso:
                 output.addMessage(__file__, 4, 'EPROT', 'Indexing by ' \
                                   'protein isoform is not supported.')
-        retriever = Retriever.GenBankRetriever(config.Retriever, output,
-                                               database)
+        retriever = Retriever.GenBankRetriever(output, database)
 
     retrieved_record = retriever.loadrecord(record_id)
 
@@ -1506,7 +1503,7 @@ def check_variant(description, config, output):
     output.addOutput('preColon', description.split(':')[0])
     output.addOutput('variant', description.split(':')[-1])
 
-    record = GenRecord.GenRecord(output, config.GenRecord)
+    record = GenRecord.GenRecord(output)
     record.record = retrieved_record
     record.checkRecord()
 
@@ -1530,7 +1527,7 @@ def check_variant(description, config, output):
     # Note: The GenRecord instance is carrying the sequence in .record.seq.
     #       So is the Mutator instance in .mutator.orig.
 
-    mutator = Mutator(record.record.seq, config.Mutator, output)
+    mutator = Mutator(record.record.seq, output)
 
     # Todo: If processing of the variant fails, we might still want to show
     # information about the record, gene, transcript.
diff --git a/mutalyzer/webservice.py b/mutalyzer/webservice.py
index e969c042..4c87b5e9 100644
--- a/mutalyzer/webservice.py
+++ b/mutalyzer/webservice.py
@@ -32,7 +32,7 @@ import socket
 from operator import itemgetter, attrgetter
 
 import mutalyzer
-from mutalyzer.config import Config
+from mutalyzer import config
 from mutalyzer.output import Output
 from mutalyzer.grammar import Grammar
 from mutalyzer.sync import CacheSync
@@ -51,7 +51,6 @@ class MutalyzerService(DefinitionBase):
     These methods are made public via a SOAP interface.
     """
     def __init__(self, environ=None):
-        self._config = Config()
         super(MutalyzerService, self).__init__(environ)
     #__init__
 
@@ -68,7 +67,7 @@ class MutalyzerService(DefinitionBase):
         @type build: string
         """
 
-        if not build in self._config.Db.dbNames :
+        if not build in config.get('dbNames'):
             L.addMessage(__file__, 4, "EARG", "EARG %s" % build)
             raise Fault("EARG",
                         "The build argument (%s) was not a valid " \
@@ -162,14 +161,14 @@ class MutalyzerService(DefinitionBase):
         @return: A list of transcripts.
         @rtype: list
         """
-        L = Output(__file__, self._config.Output)
+        L = Output(__file__)
 
         L.addMessage(__file__, -1, "INFO",
                      "Received request getTranscripts(%s %s %s %s)" % (build,
                      chrom, pos, versions))
 
         self.__checkBuild(L, build)
-        D = Db.Mapping(build, self._config.Db)
+        D = Db.Mapping(build)
 
         self.__checkChrom(L, D, chrom)
         self.__checkPos(L, pos)
@@ -198,14 +197,14 @@ class MutalyzerService(DefinitionBase):
         """
         Todo: documentation.
         """
-        L = Output(__file__, self._config.Output)
+        L = Output(__file__)
 
         L.addMessage(__file__, -1, "INFO",
                      "Received request getTranscriptsByGene(%s %s)" % (build,
                      name))
 
         self.__checkBuild(L, build)
-        D = Db.Mapping(build, self._config.Db)
+        D = Db.Mapping(build)
 
         ret = D.get_TranscriptsByGeneName(name)
 
@@ -244,13 +243,13 @@ class MutalyzerService(DefinitionBase):
         @return: A list of transcripts.
         @rtype: list
         """
-        L = Output(__file__, self._config.Output)
+        L = Output(__file__)
 
         L.addMessage(__file__, -1, "INFO",
             "Received request getTranscriptsRange(%s %s %s %s %s)" % (build,
             chrom, pos1, pos2, method))
 
-        D = Db.Mapping(build, self._config.Db)
+        D = Db.Mapping(build)
         self.__checkBuild(L, build)
 
         ret = D.get_Transcripts(chrom, pos1, pos2, method)
@@ -279,12 +278,12 @@ class MutalyzerService(DefinitionBase):
         @return: The name of the associated gene.
         @rtype: string
         """
-        L = Output(__file__, self._config.Output)
+        L = Output(__file__)
 
         L.addMessage(__file__, -1, "INFO",
                      "Received request getGeneName(%s %s)" % (build, accno))
 
-        D = Db.Mapping(build, self._config.Db)
+        D = Db.Mapping(build)
         self.__checkBuild(L, build)
 
         ret = D.get_GeneName(accno.split('.')[0])
@@ -338,13 +337,13 @@ class MutalyzerService(DefinitionBase):
           - type         ; The mutation type.
         @rtype: object
         """
-        L = Output(__file__, self._config.Output)
+        L = Output(__file__)
 
         L.addMessage(__file__, -1, "INFO",
                      "Reveived request mappingInfo(%s %s %s %s)" % (
                         LOVD_ver, build, accNo, variant))
 
-        conv = Converter(build, self._config, L)
+        conv = Converter(build, L)
         result = conv.mainMapping(accNo, variant)
 
         L.addMessage(__file__, -1, "INFO",
@@ -376,13 +375,13 @@ class MutalyzerService(DefinitionBase):
           - CDS_stop     ; CDS stop in I{c.} notation.
         @rtype: object
         """
-        O = Output(__file__, self._config.Output)
+        O = Output(__file__)
 
         O.addMessage(__file__, -1, "INFO",
                      "Received request transcriptInfo(%s %s %s)" % (LOVD_ver,
                      build, accNo))
 
-        converter = Converter(build, self._config, O)
+        converter = Converter(build, O)
         T = converter.mainTranscript(accNo)
 
         O.addMessage(__file__, -1, "INFO",
@@ -404,8 +403,8 @@ class MutalyzerService(DefinitionBase):
         @return: The accession number of a chromosome.
         @rtype: string
         """
-        D = Db.Mapping(build, self._config.Db)
-        L = Output(__file__, self._config.Output)
+        D = Db.Mapping(build)
+        L = Output(__file__)
 
         L.addMessage(__file__, -1, "INFO",
                      "Received request chromAccession(%s %s)" % (build, name))
@@ -436,8 +435,8 @@ class MutalyzerService(DefinitionBase):
         @return: The name of a chromosome.
         @rtype: string
         """
-        D = Db.Mapping(build, self._config.Db)
-        L = Output(__file__, self._config.Output)
+        D = Db.Mapping(build)
+        L = Output(__file__)
 
         L.addMessage(__file__, -1, "INFO",
                      "Received request chromName(%s %s)" % (build, accNo))
@@ -468,8 +467,8 @@ class MutalyzerService(DefinitionBase):
         @return: The name of a chromosome.
         @rtype: string
         """
-        D = Db.Mapping(build, self._config.Db)
-        L = Output(__file__, self._config.Output)
+        D = Db.Mapping(build)
+        L = Output(__file__)
 
         L.addMessage(__file__, -1, "INFO",
                      "Received request getchromName(%s %s)" % (build, acc))
@@ -504,12 +503,12 @@ class MutalyzerService(DefinitionBase):
         @return: The variant(s) in either I{g.} or I{c.} notation.
         @rtype: list
         """
-        D = Db.Mapping(build, self._config.Db)
-        O = Output(__file__, self._config.Output)
+        D = Db.Mapping(build)
+        O = Output(__file__)
         O.addMessage(__file__, -1, "INFO",
                      "Received request cTogConversion(%s %s)" % (
                      build, variant))
-        converter = Converter(build, self._config, O)
+        converter = Converter(build, O)
         variant = converter.correctChrVariant(variant)
 
         if "c." in variant :
@@ -539,7 +538,7 @@ class MutalyzerService(DefinitionBase):
                  - messages: List of (error) messages as strings.
         @rtype: object
         """
-        output = Output(__file__, self._config.Output)
+        output = Output(__file__)
         output.addMessage(__file__, -1, "INFO",
                           "Received request checkSyntax(%s)" % (variant))
 
@@ -569,10 +568,10 @@ class MutalyzerService(DefinitionBase):
         """
         Todo: documentation.
         """
-        O = Output(__file__, self._config.Output)
+        O = Output(__file__)
         O.addMessage(__file__, -1, "INFO",
                      "Received request runMutalyzer(%s)" % (variant))
-        variantchecker.check_variant(variant, self._config, O)
+        variantchecker.check_variant(variant, O)
 
         result = MutalyzerOutput()
 
@@ -630,16 +629,16 @@ class MutalyzerService(DefinitionBase):
         """
         Todo: documentation.
         """
-        O = Output(__file__, self._config.Output)
-        D = Db.Cache(self._config.Db)
+        O = Output(__file__)
+        D = Db.Cache()
 
         O.addMessage(__file__, -1, "INFO",
             "Received request getGeneAndTranscript(%s, %s)" % (genomicReference,
             transcriptReference))
-        retriever = Retriever.GenBankRetriever(self._config.Retriever, O, D)
+        retriever = Retriever.GenBankRetriever(O, D)
         record = retriever.loadrecord(genomicReference)
 
-        GenRecordInstance = GenRecord.GenRecord(O, self._config.GenRecord)
+        GenRecordInstance = GenRecord.GenRecord(O)
         GenRecordInstance.record = record
         GenRecordInstance.checkRecord()
 
@@ -696,16 +695,16 @@ class MutalyzerService(DefinitionBase):
                                       - id
                                       - product
         """
-        O = Output(__file__, self._config.Output)
-        D = Db.Cache(self._config.Db)
+        O = Output(__file__)
+        D = Db.Cache()
 
         O.addMessage(__file__, -1, "INFO",
             "Received request getTranscriptsAndInfo(%s)" % genomicReference)
-        retriever = Retriever.GenBankRetriever(self._config.Retriever, O, D)
+        retriever = Retriever.GenBankRetriever(O, D)
         record = retriever.loadrecord(genomicReference)
 
         # Todo: If loadRecord failed (e.g. DTD missing), we should abort here.
-        GenRecordInstance = GenRecord.GenRecord(O, self._config.GenRecord)
+        GenRecordInstance = GenRecord.GenRecord(O)
         GenRecordInstance.record = record
         GenRecordInstance.checkRecord()
 
@@ -810,9 +809,9 @@ class MutalyzerService(DefinitionBase):
         """
         Todo: documentation, error handling, argument checking, tests.
         """
-        O = Output(__file__, self._config.Output)
-        D = Db.Cache(self._config.Db)
-        retriever = Retriever.GenBankRetriever(self._config.Retriever, O, D)
+        O = Output(__file__)
+        D = Db.Cache()
+        retriever = Retriever.GenBankRetriever(O, D)
 
         O.addMessage(__file__, -1, "INFO",
             "Received request sliceChromosomeByGene(%s, %s, %s, %s)" % (
@@ -839,9 +838,9 @@ class MutalyzerService(DefinitionBase):
         """
         Todo: documentation, error handling, argument checking, tests.
         """
-        O = Output(__file__, self._config.Output)
-        D = Db.Cache(self._config.Db)
-        retriever = Retriever.GenBankRetriever(self._config.Retriever, O, D)
+        O = Output(__file__)
+        D = Db.Cache()
+        retriever = Retriever.GenBankRetriever(O, D)
 
         O.addMessage(__file__, -1, "INFO",
             "Received request sliceChromosome(%s, %s, %s, %s)" % (
@@ -875,7 +874,7 @@ class MutalyzerService(DefinitionBase):
             - contactEmail: The email address to contact for more information.
         @rtype: object
         """
-        output = Output(__file__, self._config.Output)
+        output = Output(__file__)
         output.addMessage(__file__, -1, 'INFO', 'Received request info')
 
         result = InfoOutput()
@@ -913,13 +912,13 @@ class MutalyzerService(DefinitionBase):
         This method is intended to be used by Mutalyzer itself to synchronize
         the cache between installations on different servers.
         """
-        output = Output(__file__, self._config.Output)
+        output = Output(__file__)
 
         output.addMessage(__file__, -1, 'INFO',
                           'Received request getCache')
 
-        database = Db.Cache(self._config.Db)
-        sync = CacheSync(self._config.Retriever, output, database)
+        database = Db.Cache()
+        sync = CacheSync(output, database)
 
         cache = sync.local_cache(created_since)
 
@@ -948,12 +947,12 @@ class MutalyzerService(DefinitionBase):
         @return: List of HGVS descriptions.
         @rtype: list(string)
         """
-        output = Output(__file__, self._config.Output)
+        output = Output(__file__)
 
         output.addMessage(__file__, -1, 'INFO',
                           'Received request getdbSNPDescription(%s)' % rs_id)
 
-        retriever = Retriever.Retriever(self._config.Retriever, output, None)
+        retriever = Retriever.Retriever(output, None)
         descriptions = retriever.snpConvert(rs_id)
 
         output.addMessage(__file__, -1, 'INFO',
diff --git a/mutalyzer/website.py b/mutalyzer/website.py
index 03e946a0..bd3328a0 100644
--- a/mutalyzer/website.py
+++ b/mutalyzer/website.py
@@ -30,7 +30,7 @@ from simpletal import simpleTAL
 
 import mutalyzer
 from mutalyzer import util
-from mutalyzer.config import Config
+from mutalyzer import config
 from mutalyzer.grammar import Grammar
 from mutalyzer import webservice
 from mutalyzer import variantchecker
@@ -42,12 +42,8 @@ from mutalyzer import Retriever
 from mutalyzer import File
 
 
-# Load configuration from configuration file
-config = Config()
-
-
 # Show web.py debugging information.
-web.config.debug = config.Output.debug
+web.config.debug = config.get('debug')
 
 
 # URL dispatch table
@@ -167,7 +163,7 @@ render = render_tal(os.path.join(mutalyzer.package_root(), 'templates'),
     'nomenclatureVersion': mutalyzer.NOMENCLATURE_VERSION,
     'releaseDate': mutalyzer.__date__,
     'release': mutalyzer.RELEASE,
-    'contactEmail': config.Retriever.email})
+    'contactEmail': config.get('email')})
 
 # web.py application
 app = web.application(urls, globals(), autoreload=False)
@@ -240,7 +236,7 @@ class Downloads:
         if not os.path.isfile(file_path):
             raise web.notfound()
         handle = open(file_path)
-        F = File.File(config.File, None)
+        F = File.File(None)
         web.header('Content-Type', F.getMimeType(handle)[0])
         web.header('Content-Disposition', 'attachment; filename="%s"' % file)
         return handle.read()
@@ -263,7 +259,7 @@ class Reference:
         The url routing currently makes sure to only call this with filenames
         of the form [a-zA-Z\._-]+.
         """
-        file_path = os.path.join(config.Retriever.cache, '%s.bz2' % file)
+        file_path = os.path.join(config.get('cache'), '%s.bz2' % file)
         if not os.path.isfile(file_path):
             raise web.notfound()
         handle = bz2.BZ2File(file_path, 'r')
@@ -286,7 +282,7 @@ class Reference:
         reconstructed from the information in the database. Because if the
         latter is the case, Mutalyzer will add it to the cache on the fly.
         """
-        file_path = os.path.join(config.Retriever.cache, '%s.bz2' % file)
+        file_path = os.path.join(config.get('cache'), '%s.bz2' % file)
         if not os.path.isfile(file_path):
             # The following is a hack to return a 404 not found status with
             # empty body (as is checked by our unit test framework, WebTest).
@@ -325,7 +321,7 @@ class GetGS:
         @return: Output of name checker if forward is set, otherwise the
                  GeneSymbol with the variant notation as string.
         """
-        O = Output(__file__, config.Output)
+        output = Output(__file__)
 
         i = web.input(mutationName=None, variantRecord=None, forward=None)
 
@@ -333,11 +329,9 @@ class GetGS:
         # We stringify the variant, because a unicode string crashes
         # Bio.Seq.reverse_complement in mapping.py:607.
 
-        # We are only interested in the legend
-        #Mutalyzer.process(str(i.mutationName), config, O)
-        variantchecker.check_variant(str(i.mutationName), config, O)
+        variantchecker.check_variant(str(i.mutationName), output)
 
-        legends = O.getOutput("legends")
+        legends = output.getOutput("legends")
 
         # Filter the transcript from the legend
         legends = [l for l in legends if "_v" in l[0]]
@@ -378,7 +372,7 @@ class SyntaxCheck:
         Parameters:
         - variant: Variant name to check.
         """
-        output = Output(__file__, config.Output)
+        output = Output(__file__)
         i = web.input()
         variant = i.variant
         if variant.find(',') >= 0:
@@ -431,13 +425,13 @@ class Snp:
         @kwarg rs_id: The dbSNP rs number (including 'rs' prefix).
         @type rs_id: string
         """
-        output = Output(__file__, config.Output)
+        output = Output(__file__)
 
         descriptions = []
 
         if rs_id:
             output.addMessage(__file__, -1, 'INFO', 'Received %s' % rs_id)
-            retriever = Retriever.Retriever(config.Retriever, output, None)
+            retriever = Retriever.Retriever(output, None)
             descriptions = retriever.snpConvert(rs_id)
             output.addMessage(__file__, -1, 'INFO',
                               'Finished processing %s' % rs_id)
@@ -484,9 +478,9 @@ class PositionConverter:
         @kwarg build: Human genome build (currently 'hg18' or 'hg19').
         @kwarg variant: Variant to convert.
         """
-        output = Output(__file__, config.Output)
+        output = Output(__file__)
 
-        avail_builds = config.Db.dbNames[::-1]
+        avail_builds = config.get('dbNames')[::-1]
 
         if build :
             avail_builds.remove(build)
@@ -503,7 +497,7 @@ class PositionConverter:
         }
 
         if build and variant:
-            converter = Converter(build, config, output)
+            converter = Converter(build, output)
 
             #Convert chr accNo to NC number
             variant = converter.correctChrVariant(variant)
@@ -589,13 +583,13 @@ class VariantInfo:
         acc = i.acc
         var = i.var
 
-        output = Output(__file__, config.Output)
+        output = Output(__file__)
 
         output.addMessage(__file__, -1, 'INFO',
                           'Received %s:%s (LOVD_ver %s, build %s)' \
                           % (acc, var, LOVD_ver, build))
 
-        converter = Converter(build, config, output)
+        converter = Converter(build, output)
 
         result = ''
 
@@ -682,7 +676,7 @@ class Check:
         @kwarg interactive: Run interactively, meaning we wrap the result in
             the site layout and include the HTML form.
         """
-        output = Output(__file__, config.Output)
+        output = Output(__file__)
 
         args = {
             'lastpost' : name
@@ -695,7 +689,7 @@ class Check:
         # Todo: The following is probably a problem elsewhere too.
         # We stringify the variant, because a unicode string crashes
         # Bio.Seq.reverse_complement in mapping.py:607.
-        variantchecker.check_variant(str(name), config, output)
+        variantchecker.check_variant(str(name), output)
         output.addMessage(__file__, -1, 'INFO',
                           'Finished processing variant %s' % name)
 
@@ -814,7 +808,7 @@ class BatchProgress:
             total = int(i.totalJobs)
         except ValueError:
             return
-        D = Db.Batch(config.Db)
+        D = Db.Batch()
         left = D.entriesLeftForJob(jobID)
         percentage = int(100 - (100 * left / float(total)))
         if i.ajax:
@@ -876,9 +870,9 @@ class BatchChecker:
                           (default), 'SyntaxChecker', 'PositionConverter', or
                           'SnpConverter'.
         """
-        O = Output(__file__, config.Output)
+        O = Output(__file__)
 
-        maxUploadSize = config.Batch.batchInputMaxSize
+        maxUploadSize = config.get('batchInputMaxSize')
 
         attr = {"messages"      : [],
                 "errors"        : [],
@@ -891,7 +885,7 @@ class BatchChecker:
                 "hideTypes"     : batchType and 'none' or '',
                 "selected"      : "0",
                 "batchType"     : batchType or "",
-                "avail_builds"  : config.Db.dbNames[::-1],
+                "avail_builds"  : config.get('dbNames')[::-1],
                 "jobID"         : None,
                 "totalJobs"     : None
         }
@@ -923,9 +917,9 @@ class BatchChecker:
                 web.ctx.status = '413 Request entity too large'
                 return 'Sorry, only files up to %s megabytes are accepted.' % (float(maxUploadSize) / 1048576)
 
-            D = Db.Batch(config.Db)
-            S = Scheduler.Scheduler(config.Scheduler, D)
-            FileInstance = File.File(config.File, O)
+            D = Db.Batch()
+            S = Scheduler.Scheduler(D)
+            FileInstance = File.File(O)
 
             # Generate the fromhost URL from which the results can be fetched
             fromHost = web.ctx.homedomain + web.ctx.homepath + '/'
@@ -970,7 +964,7 @@ class BatchResult:
         of the form \d+.
         """
         filename = 'Results_%s.txt' % result
-        handle = open(os.path.join(config.Scheduler.resultsDir, filename))
+        handle = open(os.path.join(config.get('resultsDir'), filename))
         web.header('Content-Type', 'text/plain')
         web.header('Content-Disposition',
                    'attachment; filename="%s"' % filename)
@@ -1020,7 +1014,7 @@ class Uploader:
         """
         Render reference sequence uploader form.
         """
-        maxUploadSize = config.Retriever.maxDldSize
+        maxUploadSize = config.get('maxDldSize')
         UD, errors = "", []
         args = {
             "UD"      : UD,
@@ -1063,11 +1057,11 @@ class Uploader:
         - stop: Stop position.
         - orientation: Orientation.
         """
-        maxUploadSize = config.Retriever.maxDldSize
+        maxUploadSize = config.get('maxDldSize')
 
-        O = Output(__file__, config.Output)
-        D = Db.Cache(config.Db)
-        R = Retriever.GenBankRetriever(config.Retriever, O, D)
+        O = Output(__file__)
+        D = Db.Cache()
+        R = Retriever.GenBankRetriever(O, D)
 
         UD, errors = "", []
 
diff --git a/tests/test_grammar.py b/tests/test_grammar.py
index 8aadc2a0..3cc5c425 100644
--- a/tests/test_grammar.py
+++ b/tests/test_grammar.py
@@ -8,7 +8,6 @@ import os
 from nose.tools import *
 
 import mutalyzer
-from mutalyzer.config import Config
 from mutalyzer.grammar import Grammar
 from mutalyzer.output import Output
 
@@ -22,8 +21,7 @@ class TestGrammar():
         """
         Initialize test Grammar instance.
         """
-        self.config = Config()
-        self.output = Output(__file__, self.config.Output)
+        self.output = Output(__file__)
         self.grammar = Grammar(self.output)
 
     def test_some_variants(self):
diff --git a/tests/test_mapping.py b/tests/test_mapping.py
index 036b46f6..5c7b38c6 100644
--- a/tests/test_mapping.py
+++ b/tests/test_mapping.py
@@ -6,7 +6,6 @@ Tests for the mapping module.
 #import logging; logging.basicConfig()
 from nose.tools import *
 
-from mutalyzer.config import Config
 from mutalyzer.output import Output
 from mutalyzer.mapping import Converter
 
@@ -19,14 +18,13 @@ class TestConverter():
         """
         Initialize test converter module.
         """
-        self.config = Config()
-        self.output = Output(__file__, self.config.Output)
+        self.output = Output(__file__)
 
     def _converter(self, build):
         """
         Create a Converter instance for a given build.
         """
-        return Converter(build, self.config, self.output)
+        return Converter(build, self.output)
 
     def test_converter(self):
         """
diff --git a/tests/test_mutator.py b/tests/test_mutator.py
index ee01cf2a..89579e70 100644
--- a/tests/test_mutator.py
+++ b/tests/test_mutator.py
@@ -12,7 +12,6 @@ from Bio.Seq import Seq
 
 import mutalyzer
 from mutalyzer.util import skip
-from mutalyzer.config import Config
 from mutalyzer.output import Output
 from mutalyzer import mutator
 
@@ -36,16 +35,13 @@ class TestMutator():
         """
         Initialize test mutator module.
         """
-        self.config = Config()
-        self.output = Output(__file__, self.config.Output)
+        self.output = Output(__file__)
 
     def _mutator(self, sequence):
         """
         Create a Mutator instance for a given sequence.
         """
-        return mutator.Mutator(sequence,
-                               self.config.Mutator,
-                               self.output)
+        return mutator.Mutator(sequence, self.output)
 
     def test_shiftpos_no_change(self):
         """
diff --git a/tests/test_variantchecker.py b/tests/test_variantchecker.py
index 74bbae73..c665150d 100644
--- a/tests/test_variantchecker.py
+++ b/tests/test_variantchecker.py
@@ -6,7 +6,6 @@ Tests for the variantchecker module.
 #import logging; logging.basicConfig()
 from nose.tools import *
 
-from mutalyzer.config import Config
 from mutalyzer.output import Output
 from mutalyzer.variantchecker import check_variant
 
@@ -19,16 +18,14 @@ class TestVariantchecker():
         """
         Initialize test variantchecker module.
         """
-        self.config = Config()
-        self.output = Output(__file__, self.config.Output)
+        self.output = Output(__file__)
 
     def test_deletion_in_frame(self):
         """
         Simple in-frame deletion should give a simple description on protein
         level.
         """
-        check_variant('AL449423.14(CDKN2A_v001):c.161_163del',
-                      self.config, self.output)
+        check_variant('AL449423.14(CDKN2A_v001):c.161_163del', self.output)
         assert_equal(self.output.getIndexedOutput('genomicDescription', 0),
                      'AL449423.14:g.61937_61939del')
         assert 'AL449423.14(CDKN2A_v001):c.161_163del' \
@@ -42,8 +39,7 @@ class TestVariantchecker():
         Simple in-frame insertion should give a simple description on protein
         level.
         """
-        check_variant('AL449423.14(CDKN2A_v001):c.161_162insATC',
-                      self.config, self.output)
+        check_variant('AL449423.14(CDKN2A_v001):c.161_162insATC', self.output)
         assert_equal(self.output.getIndexedOutput('genomicDescription', 0),
                      'AL449423.14:g.61938_61939insGAT')
         assert 'AL449423.14(CDKN2A_v001):c.161_162insATC' \
@@ -58,7 +54,7 @@ class TestVariantchecker():
         protein level.
         """
         check_variant('AL449423.14(CDKN2A_v001):c.161_162delinsATCCC',
-                      self.config, self.output)
+                      self.output)
         assert_equal(self.output.getIndexedOutput('genomicDescription', 0),
                      'AL449423.14:g.61938_61939delinsGGGAT')
         assert 'AL449423.14(CDKN2A_v001):c.161_162delinsATCCC' \
@@ -73,7 +69,7 @@ class TestVariantchecker():
         protein level, also with the optional deleted sequence argument.
         """
         check_variant('AL449423.14(CDKN2A_v001):c.161_162delTGinsATCCC',
-                      self.config, self.output)
+                      self.output)
         assert_equal(self.output.getIndexedOutput('genomicDescription', 0),
                      'AL449423.14:g.61938_61939delinsGGGAT')
         assert 'AL449423.14(CDKN2A_v001):c.161_162delinsATCCC' \
@@ -86,7 +82,7 @@ class TestVariantchecker():
         """
         Just a variant where we should roll.
         """
-        check_variant('NM_003002.2:c.273del', self.config, self.output)
+        check_variant('NM_003002.2:c.273del', self.output)
         wroll = self.output.getMessagesWithErrorCode('WROLLFORWARD')
         assert len(wroll) > 0
 
@@ -94,7 +90,7 @@ class TestVariantchecker():
         """
         Just a variant where we cannot roll.
         """
-        check_variant('NM_003002.2:c.274del', self.config, self.output)
+        check_variant('NM_003002.2:c.274del', self.output)
         wroll = self.output.getMessagesWithErrorCode('WROLLFORWARD')
         assert_equal(len(wroll), 0)
 
@@ -102,7 +98,7 @@ class TestVariantchecker():
         """
         Here we can roll but should not, because it is over a splice site.
         """
-        check_variant('NM_000088.3:g.459del', self.config, self.output)
+        check_variant('NM_000088.3:g.459del', self.output)
         wrollback = self.output.getMessagesWithErrorCode('IROLLBACK')
         assert len(wrollback) > 0
         wroll = self.output.getMessagesWithErrorCode('WROLLFORWARD')
@@ -113,7 +109,7 @@ class TestVariantchecker():
         Here we can roll two positions, but should roll only one because
         otherwise it is over a splice site.
         """
-        check_variant('NM_000088.3:g.494del', self.config, self.output)
+        check_variant('NM_000088.3:g.494del', self.output)
         wrollback = self.output.getMessagesWithErrorCode('IROLLBACK')
         assert len(wrollback) > 0
         wroll = self.output.getMessagesWithErrorCode('WROLLFORWARD')
@@ -123,7 +119,7 @@ class TestVariantchecker():
         """
         Here we can roll and should, we stay in the same exon.
         """
-        check_variant('NM_000088.3:g.460del', self.config, self.output)
+        check_variant('NM_000088.3:g.460del', self.output)
         wroll = self.output.getMessagesWithErrorCode('WROLLFORWARD')
         assert len(wroll) > 0
 
@@ -155,7 +151,7 @@ class TestVariantchecker():
         of AL449423.14:g.65471_65472insACT, where only the reverse roll should
         be done.
         """
-        check_variant('AL449423.14:g.65470_65471insTAC', self.config, self.output)
+        check_variant('AL449423.14:g.65470_65471insTAC', self.output)
         assert 'AL449423.14(CDKN2A_v001):c.99_100insTAG' in self.output.getOutput('descriptions')
         assert_equal ('AL449423.14:g.65471_65472insACT', self.output.getIndexedOutput('genomicDescription', 0, ''))
         assert_equal(len(self.output.getMessagesWithErrorCode('WROLLFORWARD')), 1)
@@ -165,7 +161,7 @@ class TestVariantchecker():
         Insertion that rolls on the reverse strand should not use the same
         inserted sequence in descriptions on forward and reverse strands.
         """
-        check_variant('AL449423.14:g.65471_65472insACT', self.config, self.output)
+        check_variant('AL449423.14:g.65471_65472insACT', self.output)
         assert 'AL449423.14(CDKN2A_v001):c.99_100insTAG' in self.output.getOutput('descriptions')
         assert_equal ('AL449423.14:g.65471_65472insACT', self.output.getIndexedOutput('genomicDescription', 0, ''))
         assert_equal(len(self.output.getMessagesWithErrorCode('WROLLFORWARD')), 0)
@@ -175,7 +171,7 @@ class TestVariantchecker():
         Roll warning message should only be shown for currently selected
         strand (forward).
         """
-        check_variant('AL449423.14:g.65470_65471insTAC', self.config, self.output)
+        check_variant('AL449423.14:g.65470_65471insTAC', self.output)
         assert_equal(len(self.output.getMessagesWithErrorCode('WROLLFORWARD')), 1)
         assert_equal(len(self.output.getMessagesWithErrorCode('WROLLREVERSE')), 0)
 
@@ -184,7 +180,7 @@ class TestVariantchecker():
         Roll warning message should only be shown for currently selected
         strand (reverse).
         """
-        check_variant('AL449423.14(CDKN2A_v001):c.98_99insGTA', self.config, self.output)
+        check_variant('AL449423.14(CDKN2A_v001):c.98_99insGTA', self.output)
         assert_equal(len(self.output.getMessagesWithErrorCode('WROLLFORWARD')), 0)
         assert_equal(len(self.output.getMessagesWithErrorCode('WROLLREVERSE')), 1)
 
@@ -192,7 +188,7 @@ class TestVariantchecker():
         """
         Insertion on CDS start boundary should not be included in CDS.
         """
-        check_variant('NM_000143.3:c.-1_1insCAT', self.config, self.output)
+        check_variant('NM_000143.3:c.-1_1insCAT', self.output)
         assert_equal(self.output.getIndexedOutput("newprotein", 0), None)
         # Todo: Is this a good test?
 
@@ -200,7 +196,7 @@ class TestVariantchecker():
         """
         Insertion after CDS start boundary should be included in CDS.
         """
-        check_variant('NM_000143.3:c.1_2insCAT', self.config, self.output)
+        check_variant('NM_000143.3:c.1_2insCAT', self.output)
         assert_equal(self.output.getIndexedOutput("newprotein", 0), '?')
         # Todo: Is this a good test?
 
@@ -208,8 +204,7 @@ class TestVariantchecker():
         """
         Deletion hitting one splice site should not do a protein prediction.
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.632-5_670del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.632-5_670del', self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert_equal(self.output.getOutput('removedSpliceSites'), [])
         # Todo: For now, the following is how to check if no protein
@@ -220,8 +215,7 @@ class TestVariantchecker():
         """
         Deletion of an entire exon should be possible.
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.632-5_681+7del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.632-5_681+7del', self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert_equal(self.output.getOutput('removedSpliceSites'), [2])
         # Todo: For now, the following is how to check if protein
@@ -232,8 +226,7 @@ class TestVariantchecker():
         """
         Deletion of exactly an exon should be possible.
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.632_681del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.632_681del', self.output)
         assert_equal(len(self.output.getMessagesWithErrorCode('WOVERSPLICE')), 0)
         assert_equal(self.output.getOutput('removedSpliceSites'), [2])
         # Todo: For now, the following is how to check if protein
@@ -249,8 +242,7 @@ class TestVariantchecker():
         NG_012772.1(BRCA2_v001):c.68-7_316+7del is such a variant, since
         positions 68 through 316 are exactly one exon and (316-68+1)/3 = 83.
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.68-7_316+7del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.68-7_316+7del', self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert_equal(self.output.getOutput('removedSpliceSites'), [2])
         # Todo: For now, the following is how to check if protein
@@ -262,8 +254,7 @@ class TestVariantchecker():
         """
         Deletion of two entire exons should be possible.
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.632-5_793+7del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.632-5_793+7del', self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert_equal(self.output.getOutput('removedSpliceSites'), [4])
         # Todo: For now, the following is how to check if protein
@@ -275,8 +266,7 @@ class TestVariantchecker():
         Deletion of an entire intron should be possible (fusion of remaining
         exonic parts).
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.622_674del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.622_674del', self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert_equal(self.output.getOutput('removedSpliceSites'), [2])
         # Todo: For now, the following is how to check if protein
@@ -288,8 +278,7 @@ class TestVariantchecker():
         Deletion of exactly an intron should be possible (fusion of flanking
         exons).
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.681+1_682-1del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.681+1_682-1del', self.output)
         assert_equal(self.output.getMessagesWithErrorCode('WOVERSPLICE'), [])
         assert_equal(self.output.getOutput('removedSpliceSites'), [2])
         # Note: The protein prediction is done, but 'newprotein' is not set
@@ -304,8 +293,7 @@ class TestVariantchecker():
         Deletion of an entire intron should be possible (fusion of remaining
         exonic parts).
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.622_672del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.622_672del', self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert_equal(self.output.getOutput('removedSpliceSites'), [2])
         # Todo: For now, the following is how to check if protein
@@ -317,8 +305,7 @@ class TestVariantchecker():
         """
         Deletion of an entire exon with unknown offsets should be possible.
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.632-?_681+?del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.632-?_681+?del', self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert len(self.output.getMessagesWithErrorCode('IDELSPLICE')) > 0
         # Todo: For now, the following is how to check if protein
@@ -343,8 +330,7 @@ class TestVariantchecker():
         NG_012772.1(BRCA2_v001):c.68-?_316+?del is such a variant, since
         positions 68 through 316 are exactly one exon and (316-68+1)/3 = 83.
         """
-        check_variant('NG_012772.1(BRCA2_v001):c.68-?_316+?del',
-                      self.config, self.output)
+        check_variant('NG_012772.1(BRCA2_v001):c.68-?_316+?del', self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert len(self.output.getMessagesWithErrorCode('IDELSPLICE')) > 0
         # Todo: For now, the following is how to check if protein
@@ -364,7 +350,7 @@ class TestVariantchecker():
         variant with exact positioning should be possible.
         """
         check_variant('NG_012772.1(BRCA2_v001):c.[632-?_681+?del;681+4del]',
-                      self.config, self.output)
+                      self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert len(self.output.getMessagesWithErrorCode('IDELSPLICE')) > 0
         # Todo: For now, the following is how to check if protein
@@ -384,7 +370,7 @@ class TestVariantchecker():
         also on the reverse strand.
         """
         check_variant('AL449423.14(CDKN2A_v001):c.151-?_457+?del',
-                      self.config, self.output)
+                      self.output)
         assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0
         assert len(self.output.getMessagesWithErrorCode('IDELSPLICE')) > 0
         # Todo: For now, the following is how to check if protein
@@ -405,7 +391,7 @@ class TestVariantchecker():
         of the flanking exons (as would happen using the mechanism for genomic
         references).
         """
-        check_variant('NM_018723.3:c.758_890del', self.config, self.output)
+        check_variant('NM_018723.3:c.758_890del', self.output)
         assert_equal(len(self.output.getMessagesWithErrorCode('WOVERSPLICE')), 0)
         assert_equal(self.output.getOutput('removedSpliceSites'), [2])
         # Todo: For now, the following is how to check if protein
@@ -416,12 +402,12 @@ class TestVariantchecker():
         """
         Insertion of a range is not implemented yet.
         """
-        check_variant('AB026906.1:c.274_275ins262_268', self.config, self.output)
+        check_variant('AB026906.1:c.274_275ins262_268', self.output)
         assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1)
 
     def test_delins_range(self):
         """
         Deletion/insertion of a range is not implemented yet.
         """
-        check_variant('AB026906.1:c.274delins262_268', self.config, self.output)
+        check_variant('AB026906.1:c.274delins262_268', self.output)
         assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1)
diff --git a/tests/test_webservice.py b/tests/test_webservice.py
index 5c743784..3e5f99d9 100644
--- a/tests/test_webservice.py
+++ b/tests/test_webservice.py
@@ -8,7 +8,6 @@ from mutalyzer.util import monkey_patch_suds; monkey_patch_suds()
 import os
 from datetime import datetime, timedelta
 import mutalyzer
-from mutalyzer.config import Config
 from mutalyzer.output import Output
 from mutalyzer.sync import CacheSync
 from mutalyzer import Db
@@ -226,10 +225,9 @@ class TestWebservice():
         """
         created_since = datetime.today() - timedelta(days=14)
 
-        config = Config()
-        database = Db.Cache(config.Db)
-        output = Output(__file__, config.Output)
-        sync = CacheSync(config.Retriever, output, database)
+        database = Db.Cache()
+        output = Output(__file__)
+        sync = CacheSync(output, database)
         cache = sync.local_cache(created_since)
 
         r = self.client.service.getCache(created_since)
-- 
GitLab