diff --git a/.gitignore b/.gitignore index bdc49a7..757fb4e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ cyvcf.egg-info dist cyvcf/parser.c cyvcf/parser.so +cyvcf/parser.*.so +.history diff --git a/cyvcf/parser.pyx b/cyvcf/parser.pyx index 72b3c7a..5d0a163 100644 --- a/cyvcf/parser.pyx +++ b/cyvcf/parser.pyx @@ -4,6 +4,10 @@ import csv import gzip import sys import itertools +import operator +import codecs +file=open +PY3 = sys.version_info > (3,) from . import utils @@ -34,9 +38,9 @@ HET = 1 HOM_ALT = 3 UNKNOWN = 2 -cdef _Call _parse_sample(char *sample, list samp_fmt, +cdef _Call _parse_sample(str sample, list samp_fmt, list samp_fmt_types, list samp_fmt_nums, - char *name, Record rec): + str name, Record rec): cdef dict sampdict = {x: None for x in samp_fmt} cdef list lvals @@ -92,7 +96,7 @@ cdef _Call _parse_sample(char *sample, list samp_fmt, sampdict[fmt] = vals return _Call(rec, name, sampdict) -cdef inline list _map(func, list iterable, char *bad='.'): +cdef inline list _map(func, list iterable, str bad='.'): '''``map``, but make bad values None.''' return [func(x) if x != bad else None for x in iterable] @@ -175,8 +179,9 @@ class _vcf_metadata_parser(object): cdef class _Call(object): """ A genotype call, a cell entry in a VCF file""" - cdef public bytes sample #NA12878 - cdef bytes gt_nums #'0/1' + cdef public str sample #NA12878 + cdef str gt_nums #'0/1' + # use str instead of bytes for python3 compatability # use bytes instead of char * because of C -> Python string complications # see: http://docs.cython.org/src/tutorial/strings.html cdef public Record site #instance of Record @@ -184,7 +189,7 @@ cdef class _Call(object): cdef public bint called, phased cdef list alleles - def __cinit__(self, Record site, char *sample, dict data): + def __cinit__(self, Record site, str sample, dict data): #: The ``Record`` for this ``_Call`` self.site = site #: The sample name @@ -426,7 +431,7 @@ cdef class Record(object): gt_phred_likelihoods # use bytes instead of char * because of C -> Python string complications # see: http://docs.cython.org/src/tutorial/strings.html - cdef readonly bytes CHROM, ID, FORMAT + cdef readonly str CHROM, ID, FORMAT cdef public REF cdef readonly object FILTER, QUAL cdef public int POS, start, end, num_hom_ref, num_het, num_hom_alt, \ @@ -435,8 +440,8 @@ cdef class Record(object): cdef public dict _sample_indexes cdef public bint has_genotypes - def __cinit__(self, char *CHROM, int POS, char *ID, - char *REF, list ALT, object QUAL=None, + def __cinit__(self, str CHROM, int POS, str ID, + str REF, list ALT, object QUAL=None, object FILTER=None, dict INFO=None, object FORMAT=None, dict sample_indexes=None, list samples=None, list gt_bases=None, list gt_types=None, @@ -493,6 +498,13 @@ cdef class Record(object): self.POS == other.POS and self.REF == other.REF and self.ALT == other.ALT) + elif op == 3: + return not self.__richcmp__(other, 2) + else: + ops = { 0: operator.lt, 1: operator.le, + 2: operator.eq, 3: operator.ne, + 4: operator.gt, 5: operator.ge } + return ops[op]( (self.CHROM, self.POS), (other.CHROM, other.POS) ) def __iter__(self): return iter(self.samples) @@ -534,8 +546,8 @@ cdef class Record(object): self._format_qual() or '.', self.FILTER or '.', self._format_info()]) - def __cmp__(self, other): - return cmp( (self.CHROM, self.POS), (other.CHROM, other.POS)) + # def __cmp__(self, other): + # return cmp( (self.CHROM, self.POS), (other.CHROM, other.POS)) def add_format(self, fmt): tmp = self.FORMAT + ':' + fmt @@ -660,10 +672,10 @@ cdef class Record(object): if self.is_snp: # just one alt allele alt_allele = self.ALT[0] - if ((self.REF == b'A' and alt_allele == b'G') or - (self.REF == b'G' and alt_allele == b'A') or - (self.REF == b'C' and alt_allele == b'T') or - (self.REF == b'T' and alt_allele == b'C')): + if ((self.REF == 'A' and alt_allele == 'G') or + (self.REF == 'G' and alt_allele == 'A') or + (self.REF == 'C' and alt_allele == 'T') or + (self.REF == 'T' and alt_allele == 'C')): return True else: return False else: return False @@ -775,20 +787,20 @@ cdef class Record(object): cdef class Reader(object): """ Reader for a VCF v 4.1 file, an iterator returning ``Record objects`` """ - cdef bytes _col_defn_line - cdef char _prepend_chr + cdef str _col_defn_line cdef public object reader - cdef bint compressed, prepend_chr + cdef bint compressed, _prepend_chr cdef public dict metadata, infos, filters, formats, cdef readonly dict _sample_indexes cdef list _header_lines, samp_data cdef public list samples cdef object _tabix - cdef public object filename + cdef public str filename cdef int num_samples + cdef str encoding - def __init__(self, fsock=None, filename=None, - bint compressed=False, bint prepend_chr=False): + def __init__(self, fsock=None, str filename=None, + bint compressed=False, bint prepend_chr=False, encoding='ascii'): """ Create a new Reader for a VCF file. You must specify a filename. Gzipped streams @@ -797,13 +809,14 @@ cdef class Reader(object): """ super(VCFReader, self).__init__() + self.encoding = encoding if not (fsock or filename): raise Exception('You must provide at least fsock or filename') if filename: self.filename = filename if fsock is None: - self.reader = file(filename) + self.reader = file(filename, 'rb') if fsock: self.reader = fsock @@ -814,6 +827,8 @@ cdef class Reader(object): if compressed or (filename and filename.endswith('.gz')): self.reader = gzip.GzipFile(fileobj=self.reader) + if PY3: + self.reader = codecs.getreader(self.encoding)(self.reader) #: metadata fields from header self.metadata = {} @@ -857,7 +872,10 @@ cdef class Reader(object): parser = _vcf_metadata_parser() - line = self.reader.next() + line = next(self.reader) + if PY3 and type(line) is bytes: + self.reader = codecs.getreader(self.encoding)(self.reader) + line = line.decode(self.encoding) while line.startswith('##'): self._header_lines.append(line) line = line.rstrip('\n') @@ -878,7 +896,7 @@ cdef class Reader(object): key, val = parser.read_meta(line.strip()) self.metadata[key] = val - line = self.reader.next() + line = next(self.reader) if line.startswith('#'): # the column def'n line - REQ'D self._col_defn_line = line @@ -888,10 +906,10 @@ cdef class Reader(object): self.num_samples = len(self.samples) self._sample_indexes = dict([(x,i) for (i,x) in enumerate(self.samples)]) else: - sys.exit("Expected column definition line beginning with #. Not found - exiting.") + sys.exit("Expected column definition line beginning with #. Not found - exiting.") - cdef list _map(Reader self, func, iterable, char *bad='.'): + cdef list _map(Reader self, func, iterable, str bad='.'): '''``map``, but make bad values None.''' return [func(x) if x != bad else None for x in iterable] @@ -909,7 +927,7 @@ cdef class Reader(object): cdef int i = 0 cdef int n = len(entries) - cdef char *entry_type + cdef str entry_type cdef list entry # for entry in entries: for i in xrange(n): @@ -926,18 +944,18 @@ cdef class Reader(object): else: entry_type = 'String' - if entry_type == b'Integer': + if entry_type == 'Integer': vals = entry[1].split(',') try: val = _map(int, vals) except ValueError: val = _map(float, vals) - elif entry_type == b'Float': + elif entry_type == 'Float': vals = entry[1].split(',') val = _map(float, vals) - elif entry_type == b'Flag': + elif entry_type == 'Flag': val = True - elif entry_type == b'String': + elif entry_type == 'String': if len(entry) > 1: val = entry[1] else: @@ -959,7 +977,7 @@ cdef class Reader(object): return retdict - def _parse_samples(self, Record rec, list samples, char *samp_fmt_s): + def _parse_samples(self, Record rec, list samples, str samp_fmt_s): '''Parse a sample entry according to the format specified in the FORMAT column.''' cdef list samp_fmt = samp_fmt_s.split(':') @@ -968,7 +986,7 @@ cdef class Reader(object): cdef list samp_fmt_nums = [None] * n cdef int i = 0 - cdef char *fmt + cdef str fmt # for fmt in samp_fmt: for i in xrange(n): fmt = samp_fmt[i] @@ -1045,7 +1063,7 @@ cdef class Reader(object): def __next__(self): '''Return the next record in the file.''' - line = self.reader.next().rstrip() + line = next(self.reader).rstrip() return self.parse(line) def parse(self, line): @@ -1053,20 +1071,21 @@ cdef class Reader(object): cdef list row = line.split('\t') #CHROM - cdef bytes chrom = row[0] + cdef str chrom = row[0] if self._prepend_chr: - chrom = 'chr' + str(chrom) + tmp = 'chr' + str(chrom) + chrom = tmp # POS cdef int pos = int(row[1]) # ID - cdef bytes id = row[2] + cdef str id = row[2] #REF - cdef bytes ref = row[3] + cdef str ref = row[3] #ALT cdef list alt = self._map(str, row[4].split(',')) #QUAL cdef object qual - if row[5] == b'.': + if row[5] == '.': qual = None else: qual = float(row[5]) @@ -1077,7 +1096,7 @@ cdef class Reader(object): #INFO cdef dict info = self._parse_info(row[7]) #FORMAT - cdef bytes fmt + cdef str fmt try: fmt = row[8] except IndexError: @@ -1113,13 +1132,19 @@ cdef class Reader(object): if end is None: self.reader = self._tabix.fetch(chrom, start, start+1) try: - return self.next() + return next(self) except StopIteration: return None self.reader = self._tabix.fetch(chrom, start, end) return self + def close(self): + try: + self.reader.close() + finally: + return + class Writer(object): """ VCF Writer """ diff --git a/ez_setup.py b/ez_setup.py index b74adc0..01e57ad 100644 --- a/ez_setup.py +++ b/ez_setup.py @@ -13,6 +13,7 @@ This file can also be run as a script to install or upgrade setuptools. """ +from __future__ import print_function import sys DEFAULT_VERSION = "0.6c11" DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] @@ -70,10 +71,10 @@ def _validate_md5(egg_name, data): if egg_name in md5_data: digest = md5(data).hexdigest() if digest != md5_data[egg_name]: - print >>sys.stderr, ( + print(( "md5 validation of %s failed! (Possible download problem?)" % egg_name - ) + ), file=sys.stderr) sys.exit(2) return data @@ -103,14 +104,14 @@ def do_download(): return do_download() try: pkg_resources.require("setuptools>="+version); return - except pkg_resources.VersionConflict, e: + except pkg_resources.VersionConflict as e: if was_imported: - print >>sys.stderr, ( + print(( "The required version of setuptools (>=%s) is not available, and\n" "can't be installed while this script is running. Please install\n" " a more recent version first, using 'easy_install -U setuptools'." "\n\n(Currently using %r)" - ) % (version, e.args[0]) + ) % (version, e.args[0]), file=sys.stderr) sys.exit(2) except pkg_resources.DistributionNotFound: pass @@ -129,7 +130,13 @@ def download_setuptools( with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ - import urllib2, shutil + #import urllib.request, urllib.error, urllib.parse, shutil + from future.standard_library import hooks + with hooks(): + from urllib.parse import urlparse, urlencode + from urllib.request import urlopen, Request + from urllib.error import HTTPError + import shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) @@ -155,7 +162,7 @@ def download_setuptools( version, download_base, delay, url ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) - src = urllib2.urlopen(url) + src = urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) @@ -216,10 +223,10 @@ def main(argv, version=DEFAULT_VERSION): os.unlink(egg) else: if setuptools.__version__ == '0.0.1': - print >>sys.stderr, ( + print(( "You have an obsolete version of setuptools installed. Please\n" "remove it from your system entirely before rerunning this script." - ) + ), file=sys.stderr) sys.exit(2) req = "setuptools>="+version @@ -238,8 +245,8 @@ def main(argv, version=DEFAULT_VERSION): from setuptools.command.easy_install import main main(argv) else: - print "Setuptools version",version,"or greater has been installed." - print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' + print("Setuptools version",version,"or greater has been installed.") + print('(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)') def update_md5(filenames): """Update our built-in md5 registry""" @@ -252,7 +259,7 @@ def update_md5(filenames): md5_data[base] = md5(f.read()).hexdigest() f.close() - data = [" %r: %r,\n" % it for it in md5_data.items()] + data = [" %r: %r,\n" % it for it in list(md5_data.items())] data.sort() repl = "".join(data) @@ -262,7 +269,7 @@ def update_md5(filenames): match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: - print >>sys.stderr, "Internal error!" + print("Internal error!", file=sys.stderr) sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] diff --git a/setup.py b/setup.py index 997c56f..baf1877 100644 --- a/setup.py +++ b/setup.py @@ -37,7 +37,13 @@ def build_extensions(self): if 'setuptools.extension' in sys.modules: m = sys.modules['setuptools.extension'] - m.Extension.__dict__ = m._Extension.__dict__ + for attr, val in m._Extension.__dict__.items(): + try: + setattr(m.Extension, attr, val) + except BaseException as e: + # print(e) + pass + # m.Extension.__dict__ = m._Extension.__dict__ version_py = os.path.join(os.path.dirname(__file__), 'cyvcf', 'version.py') version = open(version_py).read().strip().split('=')[-1].replace('"','') @@ -63,4 +69,4 @@ def build_extensions(self): 'License :: OSI Approved :: GNU General Public License (GPL)', 'Topic :: Scientific/Engineering :: Bio-Informatics'] - ) \ No newline at end of file + ) diff --git a/test/test_vcf.py b/test/test_vcf.py index bcfb098..f7f3630 100644 --- a/test/test_vcf.py +++ b/test/test_vcf.py @@ -1,17 +1,29 @@ import unittest import doctest import os -import commands -from StringIO import StringIO +import subprocess +try: + from StringIO import StringIO +except ImportError: # py3 + from io import StringIO import cyvcf from cyvcf import utils +import gzip + +import sys +PY3 = sys.version_info > (3,) + +file=open suite = doctest.DocTestSuite(cyvcf.parser) def fh(fname): - return file(os.path.join(os.path.dirname(__file__), fname)) + path = os.path.join(os.path.dirname(__file__), fname) + if PY3 and fname.endswith(".gz"): + return file(path, 'rb') + return file(path) class TestVcfSpecs(unittest.TestCase): @@ -68,9 +80,9 @@ def test_vcf_4_1_sv(self): # test we can walk the file at least for r in reader: - print r + print(r) for c in r: - print c + print(c) assert c # asserting False while I work out what to check @@ -135,7 +147,7 @@ class TestFreebayesOutput(TestGatkOutput): def testParse(self): reader = cyvcf.Reader(fh('freebayes.vcf')) - print reader.samples + print(reader.samples) self.assertEqual(len(reader.samples), 7) n = 0 for r in reader: @@ -173,18 +185,18 @@ def testWrite(self): records = list(reader) - map(writer.write_record, records) + list(map(writer.write_record, records)) out.seek(0) reader2 = cyvcf.Reader(out) - self.assertEquals(reader.samples, reader2.samples) - self.assertEquals(reader.formats, reader2.formats) + self.assertEqual(reader.samples, reader2.samples) + self.assertEqual(reader.formats, reader2.formats) for k in reader.infos: - self.assertEquals(reader.infos[k], reader2.infos[k], (reader.infos[k], reader2.infos[k])) + self.assertEqual(reader.infos[k], reader2.infos[k], (reader.infos[k], reader2.infos[k])) for l, r in zip(records, reader2): - self.assertEquals(l.samples, r.samples) + self.assertEqual(l.samples, r.samples) class TestRecord(unittest.TestCase): @@ -194,6 +206,7 @@ def test_num_calls(self): num_calls = (var.num_hom_ref + var.num_hom_alt + \ var.num_het + var.num_unknown) self.assertEqual(len(var.samples), num_calls) + reader.close() def test_call_rate(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) @@ -209,6 +222,7 @@ def test_call_rate(self): self.assertEqual(3.0/3.0, call_rate) elif var.POS == 1234567: self.assertEqual(2.0/3.0, call_rate) + reader.close() def test_aaf(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) @@ -224,6 +238,7 @@ def test_aaf(self): self.assertEqual(0.0/6.0, aaf) elif var.POS == 1234567: self.assertEqual(None, aaf) + reader.close() def test_pi(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) @@ -239,6 +254,7 @@ def test_pi(self): self.assertEqual(0.0/6.0, pi) elif var.POS == 1234567: self.assertEqual(None, pi) + reader.close() def test_is_snp(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) @@ -254,6 +270,7 @@ def test_is_snp(self): self.assertEqual(False, is_snp) elif var.POS == 1234567: self.assertEqual(False, is_snp) + reader.close() def test_is_indel(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) @@ -269,6 +286,7 @@ def test_is_indel(self): self.assertEqual(True, is_indel) elif var.POS == 1234567: self.assertEqual(True, is_indel) + reader.close() def test_is_transition(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) @@ -284,6 +302,7 @@ def test_is_transition(self): self.assertEqual(False, is_trans) elif var.POS == 1234567: self.assertEqual(False, is_trans) + reader.close() def test_is_deletion(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) @@ -299,6 +318,7 @@ def test_is_deletion(self): self.assertEqual(True, is_del) elif var.POS == 1234567: self.assertEqual(False, is_del) + reader.close() def test_var_type(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) @@ -314,6 +334,7 @@ def test_var_type(self): self.assertEqual("indel", type) elif var.POS == 1234567: self.assertEqual("indel", type) + reader.close() # SV tests reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) for var in reader: @@ -330,6 +351,7 @@ def test_var_type(self): self.assertEqual("sv", type) elif var.POS == 18665128: self.assertEqual("sv", type) + reader.close() def test_var_subtype(self): @@ -346,6 +368,7 @@ def test_var_subtype(self): self.assertEqual("del", subtype) elif var.POS == 1234567: self.assertEqual("unknown", subtype) + reader.close() # SV tests reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) for var in reader: @@ -362,6 +385,7 @@ def test_var_subtype(self): self.assertEqual("DUP", subtype) elif var.POS == 18665128: self.assertEqual("DUP:TANDEM", subtype) + reader.close() def test_is_sv(self): reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) @@ -379,6 +403,7 @@ def test_is_sv(self): self.assertEqual(True, is_sv) elif var.POS == 18665128: self.assertEqual(True, is_sv) + reader.close() reader = cyvcf.Reader(fh('example-4.0.vcf')) for var in reader: @@ -393,6 +418,7 @@ def test_is_sv(self): self.assertEqual(False, is_sv) elif var.POS == 1234567: self.assertEqual(False, is_sv) + reader.close() def test_is_sv_precise(self): reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) @@ -410,6 +436,7 @@ def test_is_sv_precise(self): self.assertEqual(False, is_precise) elif var.POS == 18665128: self.assertEqual(False, is_precise) + reader.close() reader = cyvcf.Reader(fh('example-4.0.vcf')) for var in reader: @@ -424,6 +451,7 @@ def test_is_sv_precise(self): self.assertEqual(False, is_precise) elif var.POS == 1234567: self.assertEqual(False, is_precise) + reader.close() def test_sv_end(self): reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) @@ -441,6 +469,7 @@ def test_sv_end(self): self.assertEqual(12686200, sv_end) elif var.POS == 18665128: self.assertEqual(18665204, sv_end) + reader.close() reader = cyvcf.Reader(fh('example-4.0.vcf')) for var in reader: @@ -455,6 +484,7 @@ def test_sv_end(self): self.assertEqual(None, sv_end) elif var.POS == 1234567: self.assertEqual(None, sv_end) + reader.close() class TestCall(unittest.TestCase): @@ -463,7 +493,7 @@ def test_phased(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) for var in reader: phases = var.gt_phases - print var + print(var) if var.POS == 14370: self.assertEqual([True, True, False], phases) if var.POS == 17330: @@ -494,7 +524,7 @@ def test_gt_types(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) for var in reader: for s in var: - print s.data + print(s.data) gt_types = [s.gt_type for s in var.samples] if var.POS == 14370: self.assertEqual([0,1,3], gt_types) @@ -511,7 +541,7 @@ def test_gt_depths(self): reader = cyvcf.Reader(fh('example-4.0.vcf')) for var in reader: for s in var: - print s.data + print(s.data) gt_depths = [s.gt_depth for s in var.samples] if var.POS == 14370: self.assertEqual([1,8,5], gt_depths) @@ -573,17 +603,17 @@ def testFetchRange(self): if not self.run: return lines = list(self.reader.fetch('20', 14370, 14370)) - self.assertEquals(len(lines), 1) + self.assertEqual(len(lines), 1) self.assertEqual(lines[0].POS, 14370) lines = list(self.reader.fetch('20', 14370, 17330)) - self.assertEquals(len(lines), 2) + self.assertEqual(len(lines), 2) self.assertEqual(lines[0].POS, 14370) self.assertEqual(lines[1].POS, 17330) lines = list(self.reader.fetch('20', 1110695, 1234567)) - self.assertEquals(len(lines), 3) + self.assertEqual(len(lines), 3) def testFetchSite(self): if not self.run: @@ -623,21 +653,21 @@ class TestFilter(unittest.TestCase): def testApplyFilter(self): - s, out = commands.getstatusoutput('python scripts/vcf_filter.py --site-quality 30 test/example-4.0.vcf sq') + s, out = subprocess.getstatusoutput('python scripts/vcf_filter.py --site-quality 30 test/example-4.0.vcf sq') #print out assert s == 0 buf = StringIO() buf.write(out) buf.seek(0) - print buf.getvalue() + print(buf.getvalue()) reader = cyvcf.Reader(buf) # check filter got into output file assert 'sq30' in reader.filters - print reader.filters + print(reader.filters) # check sites were filtered n = 0 @@ -651,7 +681,7 @@ def testApplyFilter(self): def testApplyMultipleFilters(self): - s, out = commands.getstatusoutput('python scripts/vcf_filter.py --site-quality 30 ' + s, out = subprocess.getstatusoutput('python scripts/vcf_filter.py --site-quality 30 ' '--genotype-quality 50 test/example-4.0.vcf sq mgq') assert s == 0 #print out @@ -660,7 +690,7 @@ def testApplyMultipleFilters(self): buf.seek(0) reader = cyvcf.Reader(buf) - print reader.filters + print(reader.filters) assert 'mgq50' in reader.filters assert 'sq30' in reader.filters @@ -670,20 +700,20 @@ class TestRegression(unittest.TestCase): def test_issue_16(self): reader = cyvcf.Reader(fh('issue-16.vcf')) - assert reader.next().QUAL == None + assert next(reader).QUAL == None def test_null_mono(self): # null qualities were written as blank, causing subsequent parse to fail - print os.path.abspath(os.path.join(os.path.dirname(__file__), 'null_genotype_mono.vcf')) + print(os.path.abspath(os.path.join(os.path.dirname(__file__), 'null_genotype_mono.vcf'))) p = cyvcf.Reader(fh('null_genotype_mono.vcf')) assert p.samples out = StringIO() writer = cyvcf.Writer(out, p) - map(writer.write_record, p) + list(map(writer.write_record, p)) out.seek(0) - print out.getvalue() + print(out.getvalue()) p2 = cyvcf.Reader(out) - rec = p2.next() + rec = next(p2) assert rec.samples @@ -726,7 +756,7 @@ def setUp(self): self.reader = cyvcf.Reader(fh('test.vcf')) def testRefDepth(self): - v = self.reader.next() + v = next(self.reader) self.assertEqual(v.samples[0].gt_ref_depth, -1) class TestGLInt(unittest.TestCase): diff --git a/test/test_vcf.py.bak b/test/test_vcf.py.bak new file mode 100644 index 0000000..bcfb098 --- /dev/null +++ b/test/test_vcf.py.bak @@ -0,0 +1,753 @@ +import unittest +import doctest +import os +import commands +from StringIO import StringIO + +import cyvcf +from cyvcf import utils + +suite = doctest.DocTestSuite(cyvcf.parser) + + +def fh(fname): + return file(os.path.join(os.path.dirname(__file__), fname)) + + +class TestVcfSpecs(unittest.TestCase): + + def test_vcf_4_0(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + assert reader.metadata['fileformat'] == 'VCFv4.0' + + # test we can walk the file at least + for r in reader: + + if r.POS == 1230237: + assert r.is_monomorphic + else: + assert not r.is_monomorphic + + if 'AF' in r.INFO: + self.assertEqual(type(r.INFO['AF']), type([])) + + for c in r: + assert c + + # issue 19, in the example ref the GQ is length 1 + if c.called: + self.assertEqual(type(c.data['GQ']), type(1)) + if 'HQ' in c.data and c.data['HQ'] is not None: + self.assertEqual(type(c.data['HQ']), type([])) + + + + def test_vcf_4_1(self): + return + reader = cyvcf.Reader(fh('example-4.1.vcf')) + self.assertEqual(reader.metadata['fileformat'], 'VCFv4.1') + + # contigs were added in vcf4.1 + # probably need to add a reader.contigs attribute + assert 'contig' in reader.metadata + + # test we can walk the file at least + for r in reader: + for c in r: + assert c + + # asserting False while I work out what to check + assert False + + def test_vcf_4_1_sv(self): + return + + reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) + + assert 'SVLEN' in reader.infos + + # test we can walk the file at least + for r in reader: + print r + for c in r: + print c + assert c + + # asserting False while I work out what to check + assert False + + +class TestGatkOutput(unittest.TestCase): + + filename = 'gatk.vcf' + + samples = ['BLANK', 'NA12878', 'NA12891', 'NA12892', + 'NA19238', 'NA19239', 'NA19240'] + formats = ['AD', 'DP', 'GQ', 'GT', 'PL'] + infos = ['AC', 'AF', 'AN', 'BaseQRankSum', 'DB', 'DP', 'DS', + 'Dels', 'FS', 'HRun', 'HaplotypeScore', 'InbreedingCoeff', + 'MQ', 'MQ0', 'MQRankSum', 'QD', 'ReadPosRankSum'] + + n_calls = 37 + + def setUp(self): + self.reader = cyvcf.Reader(fh(self.filename)) + + def testSamples(self): + self.assertEqual(self.reader.samples, self.samples) + + def testFormats(self): + self.assertEqual(set(self.reader.formats), set(self.formats)) + + def testInfos(self): + self.assertEqual(set(self.reader.infos), set(self.infos)) + + + def testCalls(self): + n = 0 + + for site in self.reader: + n += 1 + self.assertEqual(len(site.samples), len(self.samples)) + + + # check sample name lookup + for s in self.samples: + assert site.genotype(s) + + # check ordered access + self.assertEqual([x.sample for x in site.samples], self.samples) + self.assertEqual(len(site.gt_phred_likelihoods), len(self.samples)) + self.assertEqual(n, self.n_calls) + + +class TestFreebayesOutput(TestGatkOutput): + + filename = 'freebayes.vcf' + formats = ['AO', 'DP', 'GL', 'GLE', 'GQ', 'GT', 'QA', 'QR', 'RO'] + infos = ['AB', 'ABP', 'AC', 'AF', 'AN', 'AO', 'BVAR', 'CIGAR', + 'DB', 'DP', 'DPRA', 'EPP', 'EPPR', 'HWE', 'LEN', 'MEANALT', + 'NUMALT', 'RPP', 'MQMR', 'ODDS', 'MQM', 'PAIREDR', 'PAIRED', + 'SAP', 'XRM', 'RO', 'REPEAT', 'XRI', 'XAS', 'XAI', 'SRP', + 'XAM', 'XRS', 'RPPR', 'NS', 'RUN', 'CpG', 'TYPE'] + n_calls = 104 + + + def testParse(self): + reader = cyvcf.Reader(fh('freebayes.vcf')) + print reader.samples + self.assertEqual(len(reader.samples), 7) + n = 0 + for r in reader: + n+=1 + for x in r: + assert x + assert n == self.n_calls + +class TestSamtoolsOutput(unittest.TestCase): + + def testParse(self): + reader = cyvcf.Reader(fh('samtools.vcf')) + + self.assertEqual(len(reader.samples), 1) + self.assertEqual(sum(1 for _ in reader), 11) + + +class Test1kg(unittest.TestCase): + + def testParse(self): + reader = cyvcf.Reader(fh('1kg.vcf.gz')) + + self.assertEqual(len(reader.samples), 629) + for _ in reader: + pass + + +class TestWriter(unittest.TestCase): + + def testWrite(self): + + reader = cyvcf.Reader(fh('gatk.vcf')) + out = StringIO() + writer = cyvcf.Writer(out, reader) + + records = list(reader) + + map(writer.write_record, records) + out.seek(0) + reader2 = cyvcf.Reader(out) + + self.assertEquals(reader.samples, reader2.samples) + self.assertEquals(reader.formats, reader2.formats) + + for k in reader.infos: + self.assertEquals(reader.infos[k], reader2.infos[k], (reader.infos[k], reader2.infos[k])) + + for l, r in zip(records, reader2): + self.assertEquals(l.samples, r.samples) + +class TestRecord(unittest.TestCase): + + def test_num_calls(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + num_calls = (var.num_hom_ref + var.num_hom_alt + \ + var.num_het + var.num_unknown) + self.assertEqual(len(var.samples), num_calls) + + def test_call_rate(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + call_rate = var.call_rate + if var.POS == 14370: + self.assertEqual(3.0/3.0, call_rate) + if var.POS == 17330: + self.assertEqual(3.0/3.0, call_rate) + if var.POS == 1110696: + self.assertEqual(3.0/3.0, call_rate) + if var.POS == 1230237: + self.assertEqual(3.0/3.0, call_rate) + elif var.POS == 1234567: + self.assertEqual(2.0/3.0, call_rate) + + def test_aaf(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + aaf = var.aaf + if var.POS == 14370: + self.assertEqual(3.0/6.0, aaf) + if var.POS == 17330: + self.assertEqual(1.0/6.0, aaf) + if var.POS == 1110696: + self.assertEqual(None, aaf) + if var.POS == 1230237: + self.assertEqual(0.0/6.0, aaf) + elif var.POS == 1234567: + self.assertEqual(None, aaf) + + def test_pi(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + pi = var.nucl_diversity + if var.POS == 14370: + self.assertEqual(6.0/10.0, pi) + if var.POS == 17330: + self.assertEqual(1.0/3.0, pi) + if var.POS == 1110696: + self.assertEqual(None, pi) + if var.POS == 1230237: + self.assertEqual(0.0/6.0, pi) + elif var.POS == 1234567: + self.assertEqual(None, pi) + + def test_is_snp(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + is_snp = var.is_snp + if var.POS == 14370: + self.assertEqual(True, is_snp) + if var.POS == 17330: + self.assertEqual(True, is_snp) + if var.POS == 1110696: + self.assertEqual(True, is_snp) + if var.POS == 1230237: + self.assertEqual(False, is_snp) + elif var.POS == 1234567: + self.assertEqual(False, is_snp) + + def test_is_indel(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + is_indel = var.is_indel + if var.POS == 14370: + self.assertEqual(False, is_indel) + if var.POS == 17330: + self.assertEqual(False, is_indel) + if var.POS == 1110696: + self.assertEqual(False, is_indel) + if var.POS == 1230237: + self.assertEqual(True, is_indel) + elif var.POS == 1234567: + self.assertEqual(True, is_indel) + + def test_is_transition(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + is_trans = var.is_transition + if var.POS == 14370: + self.assertEqual(True, is_trans) + if var.POS == 17330: + self.assertEqual(False, is_trans) + if var.POS == 1110696: + self.assertEqual(False, is_trans) + if var.POS == 1230237: + self.assertEqual(False, is_trans) + elif var.POS == 1234567: + self.assertEqual(False, is_trans) + + def test_is_deletion(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + is_del = var.is_deletion + if var.POS == 14370: + self.assertEqual(False, is_del) + if var.POS == 17330: + self.assertEqual(False, is_del) + if var.POS == 1110696: + self.assertEqual(False, is_del) + if var.POS == 1230237: + self.assertEqual(True, is_del) + elif var.POS == 1234567: + self.assertEqual(False, is_del) + + def test_var_type(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + type = var.var_type + if var.POS == 14370: + self.assertEqual("snp", type) + if var.POS == 17330: + self.assertEqual("snp", type) + if var.POS == 1110696: + self.assertEqual("snp", type) + if var.POS == 1230237: + self.assertEqual("indel", type) + elif var.POS == 1234567: + self.assertEqual("indel", type) + # SV tests + reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) + for var in reader: + type = var.var_type + if var.POS == 2827693: + self.assertEqual("sv", type) + if var.POS == 321682: + self.assertEqual("sv", type) + if var.POS == 14477084: + self.assertEqual("sv", type) + if var.POS == 9425916: + self.assertEqual("sv", type) + elif var.POS == 12665100: + self.assertEqual("sv", type) + elif var.POS == 18665128: + self.assertEqual("sv", type) + + + def test_var_subtype(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + subtype = var.var_subtype + if var.POS == 14370: + self.assertEqual("ts", subtype) + if var.POS == 17330: + self.assertEqual("tv", subtype) + if var.POS == 1110696: + self.assertEqual("unknown", subtype) + if var.POS == 1230237: + self.assertEqual("del", subtype) + elif var.POS == 1234567: + self.assertEqual("unknown", subtype) + # SV tests + reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) + for var in reader: + subtype = var.var_subtype + if var.POS == 2827693: + self.assertEqual("DEL", subtype) + if var.POS == 321682: + self.assertEqual("DEL", subtype) + if var.POS == 14477084: + self.assertEqual("DEL:ME:ALU", subtype) + if var.POS == 9425916: + self.assertEqual("INS:ME:L1", subtype) + elif var.POS == 12665100: + self.assertEqual("DUP", subtype) + elif var.POS == 18665128: + self.assertEqual("DUP:TANDEM", subtype) + + def test_is_sv(self): + reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) + for var in reader: + is_sv = var.is_sv + if var.POS == 2827693: + self.assertEqual(True, is_sv) + if var.POS == 321682: + self.assertEqual(True, is_sv) + if var.POS == 14477084: + self.assertEqual(True, is_sv) + if var.POS == 9425916: + self.assertEqual(True, is_sv) + elif var.POS == 12665100: + self.assertEqual(True, is_sv) + elif var.POS == 18665128: + self.assertEqual(True, is_sv) + + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + is_sv = var.is_sv + if var.POS == 14370: + self.assertEqual(False, is_sv) + if var.POS == 17330: + self.assertEqual(False, is_sv) + if var.POS == 1110696: + self.assertEqual(False, is_sv) + if var.POS == 1230237: + self.assertEqual(False, is_sv) + elif var.POS == 1234567: + self.assertEqual(False, is_sv) + + def test_is_sv_precise(self): + reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) + for var in reader: + is_precise = var.is_sv_precise + if var.POS == 2827693: + self.assertEqual(True, is_precise) + if var.POS == 321682: + self.assertEqual(False, is_precise) + if var.POS == 14477084: + self.assertEqual(False, is_precise) + if var.POS == 9425916: + self.assertEqual(False, is_precise) + elif var.POS == 12665100: + self.assertEqual(False, is_precise) + elif var.POS == 18665128: + self.assertEqual(False, is_precise) + + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + is_precise = var.is_sv_precise + if var.POS == 14370: + self.assertEqual(False, is_precise) + if var.POS == 17330: + self.assertEqual(False, is_precise) + if var.POS == 1110696: + self.assertEqual(False, is_precise) + if var.POS == 1230237: + self.assertEqual(False, is_precise) + elif var.POS == 1234567: + self.assertEqual(False, is_precise) + + def test_sv_end(self): + reader = cyvcf.Reader(fh('example-4.1-sv.vcf')) + for var in reader: + sv_end = var.sv_end + if var.POS == 2827693: + self.assertEqual(2827680, sv_end) + if var.POS == 321682: + self.assertEqual(321887, sv_end) + if var.POS == 14477084: + self.assertEqual(14477381, sv_end) + if var.POS == 9425916: + self.assertEqual(9425916, sv_end) + elif var.POS == 12665100: + self.assertEqual(12686200, sv_end) + elif var.POS == 18665128: + self.assertEqual(18665204, sv_end) + + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + sv_end = var.sv_end + if var.POS == 14370: + self.assertEqual(None, sv_end) + if var.POS == 17330: + self.assertEqual(None, sv_end) + if var.POS == 1110696: + self.assertEqual(None, sv_end) + if var.POS == 1230237: + self.assertEqual(None, sv_end) + elif var.POS == 1234567: + self.assertEqual(None, sv_end) + + +class TestCall(unittest.TestCase): + + def test_phased(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + phases = var.gt_phases + print var + if var.POS == 14370: + self.assertEqual([True, True, False], phases) + if var.POS == 17330: + self.assertEqual([True, True, False], phases) + if var.POS == 1110696: + self.assertEqual([True, True, False], phases) + if var.POS == 1230237: + self.assertEqual([True, True, False], phases) + elif var.POS == 1234567: + self.assertEqual([False, False, False], phases) + + def test_gt_bases(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + gt_bases = [s.gt_bases for s in var.samples] + if var.POS == 14370: + self.assertEqual(['G|G', 'A|G', 'A/A'], gt_bases) + elif var.POS == 17330: + self.assertEqual(['T|T', 'T|A', 'T/T'], gt_bases) + elif var.POS == 1110696: + self.assertEqual(['G|T', 'T|G', 'T/T'], gt_bases) + elif var.POS == 1230237: + self.assertEqual(['T|T', 'T|T', 'T/T'], gt_bases) + elif var.POS == 1234567: + self.assertEqual([None, 'GTCT/GTACT', 'G/G'], gt_bases) + + def test_gt_types(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + for s in var: + print s.data + gt_types = [s.gt_type for s in var.samples] + if var.POS == 14370: + self.assertEqual([0,1,3], gt_types) + elif var.POS == 17330: + self.assertEqual([0,1,0], gt_types) + elif var.POS == 1110696: + self.assertEqual([1,1,3], gt_types) + elif var.POS == 1230237: + self.assertEqual([0,0,0], gt_types) + elif var.POS == 1234567: + self.assertEqual([None,1,3], gt_types) + + def test_gt_depths(self): + reader = cyvcf.Reader(fh('example-4.0.vcf')) + for var in reader: + for s in var: + print s.data + gt_depths = [s.gt_depth for s in var.samples] + if var.POS == 14370: + self.assertEqual([1,8,5], gt_depths) + elif var.POS == 17330: + self.assertEqual([3,5,3], gt_depths) + elif var.POS == 1110696: + self.assertEqual([6,0,4], gt_depths) + elif var.POS == 1230237: + self.assertEqual([7,4,2], gt_depths) + elif var.POS == 1234567: + self.assertEqual([4,2,3], gt_depths) + + def test_gt_ref_depths(self): + + reader = cyvcf.Reader(fh('gatk.vcf')) + for var in reader: + gt_ref_depths = [s.gt_ref_depth for s in var.samples] + if var.POS == 42522392: + self.assertEqual([6,138,169,249,248,250,250], gt_ref_depths) + elif var.POS == 42522613: + self.assertEqual([13,118,241,161,110,106,116], gt_ref_depths) + elif var.POS == 42527891: + self.assertEqual([-1,238,246,239,232,233,238], gt_ref_depths) + + def test_gt_alt_depths(self): + + reader = cyvcf.Reader(fh('gatk.vcf')) + for var in reader: + gt_alt_depths = [s.gt_alt_depth for s in var.samples] + if var.POS == 42522392: + self.assertEqual([0,107,77,0,1,0,0], gt_alt_depths) + elif var.POS == 42522613: + self.assertEqual([4,127,0,85,132,135,126], gt_alt_depths) + elif var.POS == 42527891: + self.assertEqual([-1,7,3,11,16,14,11], gt_alt_depths) + + def test_gt_quals(self): + + reader = cyvcf.Reader(fh('gatk.vcf')) + for var in reader: + gt_quals = [s.gt_qual for s in var.samples] + if var.POS == 42522392: + self.assertEqual([18.04,99,99,99,99,99,99], gt_quals) + elif var.POS == 42522613: + self.assertEqual([62.64,99,99,99,99,99,99], gt_quals) + elif var.POS == 42527891: + self.assertEqual([-1,13.70,5.97,31.42,49.09,52.10,12.71], gt_quals) + + +class TestTabix(unittest.TestCase): + + def setUp(self): + self.reader = cyvcf.Reader(fh('tb.vcf.gz')) + + self.run = cyvcf.parser.pysam is not None + + + def testFetchRange(self): + if not self.run: + return + lines = list(self.reader.fetch('20', 14370, 14370)) + self.assertEquals(len(lines), 1) + self.assertEqual(lines[0].POS, 14370) + + lines = list(self.reader.fetch('20', 14370, 17330)) + self.assertEquals(len(lines), 2) + self.assertEqual(lines[0].POS, 14370) + self.assertEqual(lines[1].POS, 17330) + + + lines = list(self.reader.fetch('20', 1110695, 1234567)) + self.assertEquals(len(lines), 3) + + def testFetchSite(self): + if not self.run: + return + site = self.reader.fetch('20', 14370) + assert site.POS == 14370 + + site = self.reader.fetch('20', 14369) + assert site is None + + + + +class TestOpenMethods(unittest.TestCase): + + samples = 'NA00001 NA00002 NA00003'.split() + + def testOpenFilehandle(self): + r = cyvcf.Reader(fh('example-4.0.vcf')) + self.assertEqual(self.samples, r.samples) + self.assertEqual('example-4.0.vcf', os.path.split(r.filename)[1]) + + def testOpenFilename(self): + r = cyvcf.Reader(filename='test/example-4.0.vcf') + self.assertEqual(self.samples, r.samples) + + def testOpenFilehandleGzipped(self): + r = cyvcf.Reader(fh('tb.vcf.gz')) + self.assertEqual(self.samples, r.samples) + + def testOpenFilenameGzipped(self): + r = cyvcf.Reader(filename='test/tb.vcf.gz') + self.assertEqual(self.samples, r.samples) + + +class TestFilter(unittest.TestCase): + + + def testApplyFilter(self): + s, out = commands.getstatusoutput('python scripts/vcf_filter.py --site-quality 30 test/example-4.0.vcf sq') + #print out + assert s == 0 + buf = StringIO() + buf.write(out) + buf.seek(0) + + print buf.getvalue() + reader = cyvcf.Reader(buf) + + + # check filter got into output file + assert 'sq30' in reader.filters + + print reader.filters + + # check sites were filtered + n = 0 + for r in reader: + if r.QUAL < 30: + assert 'sq30' in r.FILTER + n += 1 + else: + assert r.FILTER is None or 'sq30' not in r.FILTER + assert n == 2 + + + def testApplyMultipleFilters(self): + s, out = commands.getstatusoutput('python scripts/vcf_filter.py --site-quality 30 ' + '--genotype-quality 50 test/example-4.0.vcf sq mgq') + assert s == 0 + #print out + buf = StringIO() + buf.write(out) + buf.seek(0) + reader = cyvcf.Reader(buf) + + print reader.filters + + assert 'mgq50' in reader.filters + assert 'sq30' in reader.filters + + +class TestRegression(unittest.TestCase): + + def test_issue_16(self): + reader = cyvcf.Reader(fh('issue-16.vcf')) + assert reader.next().QUAL == None + + def test_null_mono(self): + # null qualities were written as blank, causing subsequent parse to fail + print os.path.abspath(os.path.join(os.path.dirname(__file__), 'null_genotype_mono.vcf')) + p = cyvcf.Reader(fh('null_genotype_mono.vcf')) + assert p.samples + out = StringIO() + writer = cyvcf.Writer(out, p) + map(writer.write_record, p) + out.seek(0) + print out.getvalue() + p2 = cyvcf.Reader(out) + rec = p2.next() + assert rec.samples + + +class TestUtils(unittest.TestCase): + + def test_walk(self): + # easy case: all same sites + reader1 = cyvcf.Reader(fh('example-4.0.vcf')) + reader2 = cyvcf.Reader(fh('example-4.0.vcf')) + reader3 = cyvcf.Reader(fh('example-4.0.vcf')) + + n = 0 + for x in utils.walk_together(reader1, reader2, reader3): + assert len(x) == 3 + assert (x[0] == x[1]) and (x[1] == x[2]) + n+= 1 + assert n == 5 + + # artificial case 2 from the left, 2 from the right, 2 together, 1 from the right, 1 from the left + + expected = 'llrrttrl' + reader1 = cyvcf.Reader(fh('walk_left.vcf')) + reader2 = cyvcf.Reader(fh('example-4.0.vcf')) + + for ex, recs in zip(expected, utils.walk_together(reader1, reader2)): + + if ex == 'l': + assert recs[0] is not None + assert recs[1] is None + if ex == 'r': + assert recs[1] is not None + assert recs[0] is None + if ex == 't': + assert recs[0] is not None + assert recs[1] is not None + + +class TestAD(unittest.TestCase): + def setUp(self): + self.reader = cyvcf.Reader(fh('test.vcf')) + + def testRefDepth(self): + v = self.reader.next() + self.assertEqual(v.samples[0].gt_ref_depth, -1) + +class TestGLInt(unittest.TestCase): + def setUp(self): + self.reader = cyvcf.Reader(fh('test-gl.vcf')) + def testGLInt(self): + v = next(self.reader) + self.assertEqual(v.samples[0].gt_phred_likelihoods, None) + + + +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestAD)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestGatkOutput)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFreebayesOutput)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestSamtoolsOutput)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestWriter)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestTabix)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestOpenMethods)) +#suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFilter)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(Test1kg)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestRecord)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCall)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestRegression)) +suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestGLInt))