diff --git a/README b/README index 3f019a0c0699cc90171f9dc3030307146fd932de..b18f7f9a78a8e60c16066c20dd09091502c2c79b 100644 --- a/README +++ b/README @@ -19,8 +19,14 @@ Coding style guide: https://github.com/ask/celery +Run the test with (from the package root, or the /tests directory): + MUTALYZER_ENV=test nosetests + + Todo: +* Fix mutalyzer/UCSC_update.py. +* Test all uses of mkstemp(). * https://www.mutalyzer.nl/projects/mutalyzer2/changeset?old_path=%2Ftrunk&old=228&new_path=%2Fbranches%2Fexon-deletions-branch&new=228#file5 * Accept a --config command line argument for a configuration file location. * Document integration, deployment, release management, etc. diff --git a/bin/mutalyzer b/bin/mutalyzer index c1af903257df91e05b936af06169335e708b04b6..912ab2c147a516c0c0928bce0efe9556f0be6542 100755 --- a/bin/mutalyzer +++ b/bin/mutalyzer @@ -184,12 +184,4 @@ if __name__ == '__main__': print 'Please provide a variant' sys.exit(1) - # Todo: Fix Mutalyzer to not depend on working directory - if not os.path.dirname(__file__) or os.path.dirname(__file__) == '.': - os.chdir('..') - else: - root_dir = os.path.split(os.path.dirname(__file__))[0] - if root_dir: - os.chdir(root_dir) - main(sys.argv[1]) diff --git a/mutalyzer/Db.py b/mutalyzer/Db.py index f7f2f45160645806c03129d99585764fe28856e8..caa7e6832ab205360092e11751478cd966d0ccc1 100644 --- a/mutalyzer/Db.py +++ b/mutalyzer/Db.py @@ -563,11 +563,11 @@ class Remote(Db) : # Convert the results to a tab delimited file. for i in self.query(statement) : for j in i : - handle.write(str(j) + chr(0x09)) # 0x09 is a TAB. - handle.write('\n') + os.write(handle, str(j) + chr(0x09)) # 0x09 is a TAB. + os.write(handle, '\n') #for - handle.close() + os.close(handle) return filename #get_Update #Remote diff --git a/mutalyzer/File.py b/mutalyzer/File.py index c7607d833b777210f6c0d8da4b8eb18582298350..0be88cfcee74629c0d89701626b1ca61f159cb73 100644 --- a/mutalyzer/File.py +++ b/mutalyzer/File.py @@ -89,8 +89,8 @@ class File() : # Dump the content of the stream pointed to by handle into the file. handle.seek(0) - write_handle.write(handle.read()) - write_handle.close() + os.write(write_handle, handle.read()) + os.close(write_handle) # Open the file with func(). ret = func(filename) diff --git a/mutalyzer/Scheduler.py b/mutalyzer/Scheduler.py index a23b2d1493c72538e62ee0fbc2b2975784abc7ac..455baa5af46696c422ea59cf1f793cdd81d697a5 100644 --- a/mutalyzer/Scheduler.py +++ b/mutalyzer/Scheduler.py @@ -21,14 +21,14 @@ import os # os.path.exists import smtplib # smtplib.STMP from email.mime.text import MIMEText # MIMEText +import mutalyzer +from mutalyzer import variantchecker +from mutalyzer.grammar import Grammar from mutalyzer.config import Config from mutalyzer.output import Output from mutalyzer import Mapper # Mapper.Converter from mutalyzer import Retriever # Retriever.Retriever -from mutalyzer import variantchecker -from mutalyzer.grammar import Grammar - __all__ = ["Scheduler"] @@ -145,6 +145,8 @@ class Scheduler() : @arg url: The url containing the results @type url: string """ + if mutalyzer.is_test(): + return #TODO: Handle Connection errors in a try, except clause #Expected errors: socket.error diff --git a/mutalyzer/__init__.py b/mutalyzer/__init__.py index 20be9eafb9d58e0c583d4b3edfb88acc09a260be..4cb36655300d2822b67462f8c8b8f836232f7f64 100644 --- a/mutalyzer/__init__.py +++ b/mutalyzer/__init__.py @@ -27,4 +27,24 @@ NOMENCLATURE_VERSION = '.'.join(NOMENCLATURE_VERSION_INFO) def package_root(): - return os.path.split(__file__)[0] + """ + Get the absolute path to the mutalyzer package. This is usefull for + things like locating HTML templates (which are in a subdirectory of the + package). + + @return: Absolute path to the mutalyzer package. + @rtype: string + """ + return os.path.realpath(os.path.split(__file__)[0]) + + +def is_test(): + """ + Check if we are in a test environment. This is determined by the + MUTALYZER_ENV environment variable, which should then be set to 'test'. + + @return: True if we are in a test environment, False otherwise. + @rtype: bool + """ + return 'MUTALYZER_ENV' in os.environ \ + and os.environ['MUTALYZER_ENV'] == 'test' diff --git a/mutalyzer/config.py b/mutalyzer/config.py index e874215f9ff4778294cd3d04e7b4a1ff4d8417ed..fe898a3ee3360e772a571a65fda0846818aaee59 100644 --- a/mutalyzer/config.py +++ b/mutalyzer/config.py @@ -6,8 +6,11 @@ module. import os +import tempfile from configobj import ConfigObj +import mutalyzer + class ConfigurationError(Exception): pass @@ -135,6 +138,14 @@ class Config(): self.GenRecord.spliceAlarm = int(config["spliceAlarm"]) self.GenRecord.spliceWarn = int(config["spliceWarn"]) + # If we are in a testing environment, use a temporary file for + # logging. + if mutalyzer.is_test(): + handle, filename = tempfile.mkstemp(suffix='.log', + prefix='mutalyzer-tests-') + os.close(handle) + self.Output.log = filename + except KeyError as e: raise ConfigurationError('Missing configuration value: %s' % e) #__init__ diff --git a/mutalyzer/webservice.py b/mutalyzer/webservice.py index 2562fa41890c0b5bc5aa6acea63a63c0b6875acf..0188b4d16395664478844be148a633df28979d7e 100644 --- a/mutalyzer/webservice.py +++ b/mutalyzer/webservice.py @@ -891,16 +891,11 @@ soap_application = Application([MutalyzerService], application = wsgi.Application(soap_application) -# Todo: Fix Mutalyzer to not depend on working directory -if not __name__ == '__main__': - os.chdir(os.path.dirname(__file__)) - - # We can also use the built-in webserver by executing this file directly -if __name__ == '__main__': - # Todo: add a main() function or something, and create an executable - # wrapper in bin/. - from wsgiref.simple_server import make_server - print 'Listening to http://localhost:8081/' - print 'WDSL file is at http://localhost:8081/?wsdl' - make_server('localhost', 8081, application).serve_forever() +#if __name__ == '__main__': +# # Todo: add a main() function or something, and create an executable +# # wrapper in bin/. +# from wsgiref.simple_server import make_server +# print 'Listening to http://localhost:8081/' +# print 'WDSL file is at http://localhost:8081/?wsdl' +# make_server('localhost', 8081, application).serve_forever() diff --git a/mutalyzer/wsgi.py b/mutalyzer/wsgi.py index 4bd4f47e9ded55c84db8412644b276163599a29e..8cafa1c342a8623f6e45203eb5dba4824050a24f 100644 --- a/mutalyzer/wsgi.py +++ b/mutalyzer/wsgi.py @@ -194,7 +194,8 @@ class render_tal: # TAL template render -render = render_tal('templates', globals={ +render = render_tal(os.path.join(mutalyzer.package_root(), 'templates'), + globals={ 'version': mutalyzer.__version__, 'nomenclatureVersion': mutalyzer.NOMENCLATURE_VERSION, 'releaseDate': mutalyzer.__date__, @@ -238,9 +239,10 @@ class Download: The url routing currently makes sure to only call this with filenames of the form [a-zA-Z-]+\.(?:py|cs). """ - if not os.path.isfile("templates/" + file): + file_path = os.path.join(mutalyzer.package_root(), 'templates', file) + if not os.path.isfile(file_path): raise web.notfound() - content = open('templates/' + file, 'r').read() + content = open(file_path, 'r').read() # Force downloading web.header('Content-Type', 'text/plain') web.header('Content-Disposition', 'attachment; filename="%s"' % file) @@ -266,9 +268,11 @@ class Downloads: The url routing currently makes sure to only call this with filenames of the form [a-zA-Z\._-]+. """ - if not os.path.isfile("templates/downloads/" + file): + file_path = os.path.join(mutalyzer.package_root(), + 'templates', 'downloads', file) + if not os.path.isfile(file_path): raise web.notfound() - handle = open("templates/downloads/" + file) + handle = open(file_path) F = File.File(config.File, None) web.header('Content-Type', F.getMimeType(handle)[0]) web.header('Content-Disposition', 'attachment; filename="%s"' % file) @@ -292,10 +296,10 @@ class Reference: The url routing currently makes sure to only call this with filenames of the form [a-zA-Z\._-]+. """ - fileName = "%s/%s.bz2" % (config.Retriever.cache, file) - if not os.path.isfile(fileName): + file_path = os.path.join(config.Retriever.cache, '%s.bz2' % file) + if not os.path.isfile(file_path): raise web.notfound() - handle = bz2.BZ2File(fileName, 'r') + handle = bz2.BZ2File(file_path, 'r') web.header('Content-Type', 'text/plain') web.header('Content-Disposition', 'attachment; filename="%s"' % file) return handle.read() @@ -1085,7 +1089,8 @@ class Documentation: """ url = web.ctx.homedomain + web.ctx.homepath + WEBSERVICE_LOCATION wsdl_handle = StringIO(webservice.soap_application.get_wsdl(url)) - xsl_handle = open(WSDL_VIEWER, 'r') + xsl_handle = open(os.path.join(mutalyzer.package_root(), WSDL_VIEWER), + 'r') wsdl_doc = etree.parse(wsdl_handle) xsl_doc = etree.parse(xsl_handle) transform = etree.XSLT(xsl_doc) @@ -1116,15 +1121,5 @@ class Static: return getattr(render, page)() -if __name__ == '__main__': - # Todo: add a main() function or something, and create an executable - # wrapper in bin/. - # Usage: - # ./src/wsgi.py [port] - app.run() -else: - # WSGI application - # Todo: Fix Mutalyzer to not depend on working directory - #os.chdir(os.path.dirname(__file__)) - os.chdir(mutalyzer.package_root()) - application = app.wsgifunc() +# WSGI application +application = app.wsgifunc() diff --git a/tests/config b/tests/config deleted file mode 100644 index 4fb75eab7966b6f9fbc576da69f2211a7df88de3..0000000000000000000000000000000000000000 --- a/tests/config +++ /dev/null @@ -1,157 +0,0 @@ -# -# Mutalyzer config file. -# -# Copy this file to /etc/mutalyzer/config or ~/.config/mutalyzer/config and -# modify to suit your preferences. - -# -# These settings are used by the Retriever module. -# - -# Use this email address for retrieval of records at the NCBI. -email = "m.vermaat.hg@lumc.nl" - -# The cache directory. -cache = "/var/cache/mutalyzer" - -# The maximum size of the cache in megabytes. -cachesize = 50 - -# The maximum size of a downloaded GenBank file in megabytes. -maxDldSize = 10 - -# The minimum size of a downloaded GenBank file in bytes. -minDldSize = 512 - -# The URL from where LRG files are fetched -lrgurl = "ftp://ftp.ebi.ac.uk/pub/databases/lrgex/" - - -# -# These settings are used by the Db module. -# - -# Internal database. -internalDb = "mutalyzer" - -# MySQL mapping database names. -dbNames = "hg18", "hg19" - -# MySQL username for the local databases (internalDb and dbNames). -LocalMySQLuser = "mutalyzer" - -# Host name for the local databases. -LocalMySQLhost = "localhost" - -# MySQL username for the UCSC database. -RemoteMySQLuser = "genome" - -# Host name for the UCSC database. -RemoteMySQLhost = "genome-mysql.cse.ucsc.edu" - -# Retrieve all entries modified within a certain number of days. -UpdateInterval = 7 - - -# -# These settings are used by the Output module. -# - -# Name and location of the log file. -log = "/tmp/mutalyzer-tests.log" - -# Prefix for each log message. -datestring = "%Y-%m-%d %H:%M:%S" - -# Message levels: -# -# 0 : Debug ; Show all messages. -# 1 : Info ; Show all messages except debug messages. -# 2 : Warning ; Show warning, error and fatal messages. -# 3 : Error ; Show error and fatal messages. -# 4 : Fatal ; Only show fatal messages. -# 5 : Off ; Show nothing. - -# Level of logged messages. -loglevel = 3 - -# Level of output messages. -outputlevel = 1 - - -# -# These settings are used by the Mutator module. -# - -# Length of the flanking sequences (used in the visualisation of mutations). -flanksize = 25 - -# Maximum length of visualised mutations. -maxvissize = 25 - -# Length of the flanking sequences of the clipped mutations (see maxvissize). -flankclipsize = 6 - - -# -# These settings are used by the Scheduler module. -# - -# Name of the batch process. -processName = "MutalyzerBatch2" - -# Return e-mail address. -mailFrom = "noreply@humgen.nl" - -# Subject of the message. -mailSubject = "Result of Mutalyzer batch check." - -# Location of the results. -resultsDir = "/var/cache/mutalyzer" - -# Location of the PID file. -PIDfile = "/var/run/mutalyzer/mutalyzer-batchd.pid" - -# Maximum size for uploaded batch input files in megabytes. -batchInputMaxSize = 5 - -# The output header for NameChecking -nameCheckOutHeader = "Input", "Errors | Messages", "AccNo", "Genesymbol", "Variant", "Reference Sequence Start Descr.", "Coding DNA Descr.", "Protein Descr.", "GeneSymbol Coding DNA Descr.", "GeneSymbol Protein Descr.", "Genomic Reference", "Coding Reference", "Protein Reference", "Affected Transcripts", "Affected Proteins" - -# The output header for SyntaxChecking -syntaxCheckOutHeader = "Input", "Status" - -# The output header for PositionConverter -positionConverterOutHeader = "Input Variant", "Errors", "Chromosomal Variant", "Coding Variant(s)" - -# The output header for SnpConverter -snpConverterOutHeader = "Input Variant", "HGVS description(s)", "Errors | Messages" - - -# -# These settings are used by the File module. -# - -# Amount of bytes to be read for determining the file type. -bufSize = 32768 - -# The obligatory header in batch request files. -header = "AccNo", "Genesymbol", "Mutation" - -# Threshold for Batch Jobs -threshold = 0.05 - - -# -# These settings are used by the GenRecord module. -# - -# Number of upstream nucleotides when searching for a transcript. -upstream = 5000 - -# Number of downstream nucleotides when searching for a transcript. -downstream = 2000 - -spliceAlarm = 2 - -spliceWarn = 5 diff --git a/tests/test_grammar.py b/tests/test_grammar.py index c5564a80ccfa152ff6c559b5d4be68de1aeaef46..8aadc2a0c3a296736684d4550c01e3f190fdb9a8 100644 --- a/tests/test_grammar.py +++ b/tests/test_grammar.py @@ -13,13 +13,6 @@ from mutalyzer.grammar import Grammar from mutalyzer.output import Output -# If we remove the os.chdir below, this is no longer necessary -CONFIG = os.path.realpath('config') - -# Todo: Fix Mutalyzer to not depend on working directory -os.chdir(mutalyzer.package_root()) - - class TestGrammar(): """ Test the mytalyzer.grammar module. @@ -29,7 +22,7 @@ class TestGrammar(): """ Initialize test Grammar instance. """ - self.config = Config(CONFIG) + self.config = Config() self.output = Output(__file__, self.config.Output) self.grammar = Grammar(self.output) diff --git a/tests/test_mutalyzer.py b/tests/test_mutalyzer.py index 52ecf1240f533fd5057ece8e57de26cd106577f0..6013695cee77efc05e1708cd80cb3a4522e3fed9 100644 --- a/tests/test_mutalyzer.py +++ b/tests/test_mutalyzer.py @@ -16,13 +16,6 @@ from mutalyzer.output import Output from mutalyzer.variantchecker import check_variant -# If we remove the os.chdir below, this is no longer necessary -CONFIG = os.path.realpath('config') - -# Todo: Fix Mutalyzer to not depend on working directory -os.chdir(mutalyzer.package_root()) - - class TestMutalyzer(): """ Test the Mutalyzer module. @@ -32,7 +25,7 @@ class TestMutalyzer(): """ Initialize test Mutalyzer module. """ - self.config = Config(CONFIG) + self.config = Config() self.output = Output(__file__, self.config.Output) def test_roll(self): diff --git a/tests/test_mutator.py b/tests/test_mutator.py index b0bf933f5098597d4760a5af8ede0b493715a926..5d64fe9e7e3cb694ca8b215334110dfc554e8741 100644 --- a/tests/test_mutator.py +++ b/tests/test_mutator.py @@ -16,13 +16,6 @@ from mutalyzer.output import Output from mutalyzer import mutator -# If we remove the os.chdir below, this is no longer necessary -CONFIG = os.path.realpath('config') - -# Todo: Fix Mutalyzer to not depend on working directory -os.chdir(mutalyzer.package_root()) - - def _seq(length): """ Return random DNA sequence of given length. @@ -42,7 +35,7 @@ class TestMutator(): """ Initialize test mutator module. """ - self.config = Config(CONFIG) + self.config = Config() self.output = Output(__file__, self.config.Output) def _mutator(self, sequence): diff --git a/tests/test_webservice.py b/tests/test_webservice.py index df94d12376001a46248f3daed17560b074a13277..05e29713066666703a7197d8a1fd4c557f314952 100644 --- a/tests/test_webservice.py +++ b/tests/test_webservice.py @@ -3,6 +3,7 @@ Tests for the SOAP interface to Mutalyzer. """ +import os import logging; logging.raiseExceptions = 0 import urllib2 from suds.client import Client diff --git a/tests/test_wsgi.py b/tests/test_wsgi.py index f5e399207bd4d792f44eb91c7a2835e7b65e57e1..4b79b600558f3e1ea5c01206dce944d2a4f2a843 100644 --- a/tests/test_wsgi.py +++ b/tests/test_wsgi.py @@ -22,10 +22,6 @@ import mutalyzer from mutalyzer.wsgi import application -# Todo: Fix Mutalyzer to not depend on working directory -os.chdir(mutalyzer.package_root()) - - class TestWSGI(): """ Test the Mutalyzer WSGI interface. @@ -507,7 +503,7 @@ facilisi.""" @todo: Test if returned genomic reference can indeed be used now. """ - test_genbank_file = '../tests/data/AB026906.1.gb' + test_genbank_file = os.path.join(os.path.split(mutalyzer.package_root())[0], 'tests/data/AB026906.1.gb') r = self.app.get('/upload') form = r.forms[0] form['invoermethode'] = 'file'