diff -Nru python-pysam-0.15.1+ds/debian/changelog python-pysam-0.15.2+ds/debian/changelog --- python-pysam-0.15.1+ds/debian/changelog 2018-09-14 08:44:51.000000000 +0000 +++ python-pysam-0.15.2+ds/debian/changelog 2019-01-17 09:25:11.000000000 +0000 @@ -1,3 +1,15 @@ +python-pysam (0.15.2+ds-1) unstable; urgency=medium + + * Team upload. + * New upstream version + * Standards-Version: 4.3.0, no changes needed + * added Py2 and Py3 versions of ${python:Provides} + * Fix lintian found spelling typos. + * debian/tests/control.autodep8 → debian/tests/control. + * remove errant log.txt from the packages. + + -- Michael R. Crusoe Thu, 17 Jan 2019 01:25:11 -0800 + python-pysam (0.15.1+ds-1) unstable; urgency=medium * Team upload. diff -Nru python-pysam-0.15.1+ds/debian/control python-pysam-0.15.2+ds/debian/control --- python-pysam-0.15.1+ds/debian/control 2018-09-14 08:40:17.000000000 +0000 +++ python-pysam-0.15.2+ds/debian/control 2019-01-17 09:23:41.000000000 +0000 @@ -22,7 +22,7 @@ bcftools (>= 1.9) , python-pytest , python3-pytest -Standards-Version: 4.2.1 +Standards-Version: 4.3.0 Vcs-Browser: https://salsa.debian.org/med-team/python-pysam Vcs-Git: https://salsa.debian.org/med-team/python-pysam.git Homepage: http://pysam.readthedocs.org/en/latest @@ -32,6 +32,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends} +Provides: ${python:Provides} Description: interface for the SAM/BAM sequence alignment and mapping format (Python 2) Pysam is a Python module for reading and manipulating Samfiles. It's a lightweight wrapper of the samtools C-API. Pysam also includes an interface @@ -44,6 +45,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${python3:Depends} +Provides: ${python3:Provides} Description: interface for the SAM/BAM sequence alignment and mapping format (Python 3) Pysam is a Python module for reading and manipulating Samfiles. It's a lightweight wrapper of the samtools C-API. Pysam also includes an interface diff -Nru python-pysam-0.15.1+ds/debian/patches/series python-pysam-0.15.2+ds/debian/patches/series --- python-pysam-0.15.1+ds/debian/patches/series 2018-09-14 08:44:51.000000000 +0000 +++ python-pysam-0.15.2+ds/debian/patches/series 2019-01-17 09:23:41.000000000 +0000 @@ -1,2 +1,3 @@ skip_test_remote.patch skip_test_needing_missing_data.patch +spelling diff -Nru python-pysam-0.15.1+ds/debian/patches/spelling python-pysam-0.15.2+ds/debian/patches/spelling --- python-pysam-0.15.1+ds/debian/patches/spelling 1970-01-01 00:00:00.000000000 +0000 +++ python-pysam-0.15.2+ds/debian/patches/spelling 2019-01-17 09:23:41.000000000 +0000 @@ -0,0 +1,115 @@ +From: Michael R. Crusoe +Subject: Fix spelling typos, courtesy of lintian +--- python-pysam.orig/bcftools/filter.c ++++ python-pysam/bcftools/filter.c +@@ -993,7 +993,7 @@ + } + static int func_npass(filter_t *flt, bcf1_t *line, token_t *rtok, token_t **stack, int nstack) + { +- if ( nstack==0 ) error("Error parsing the expresion\n"); ++ if ( nstack==0 ) error("Error parsing the expression\n"); + token_t *tok = stack[nstack - 1]; + if ( !tok->nsamples ) error("The function %s works with FORMAT fields\n", rtok->tag); + +--- python-pysam.orig/bcftools/filter.c.pysam.c ++++ python-pysam/bcftools/filter.c.pysam.c +@@ -995,7 +995,7 @@ + } + static int func_npass(filter_t *flt, bcf1_t *line, token_t *rtok, token_t **stack, int nstack) + { +- if ( nstack==0 ) error("Error parsing the expresion\n"); ++ if ( nstack==0 ) error("Error parsing the expression\n"); + token_t *tok = stack[nstack - 1]; + if ( !tok->nsamples ) error("The function %s works with FORMAT fields\n", rtok->tag); + +--- python-pysam.orig/pysam/libcalignedsegment.pyx ++++ python-pysam/pysam/libcalignedsegment.pyx +@@ -2244,7 +2244,7 @@ + *value*. + + An existing value of the same *tag* will be overwritten unless +- *replace* is set to False. This is usually not recommened as a ++ *replace* is set to False. This is usually not recommended as a + tag may only appear once in the optional alignment section. + + If *value* is None, the tag will be deleted. +--- python-pysam.orig/pysam/libcalignmentfile.pyx ++++ python-pysam/pysam/libcalignmentfile.pyx +@@ -1023,7 +1023,7 @@ + + See :meth:`~pysam.HTSFile.parse_region` for more information + on how genomic regions can be specified. :term:`reference` and +- `end` are also accepted for backward compatiblity as synonyms ++ `end` are also accepted for backward compatibility as synonyms + for :term:`contig` and `stop`, respectively. + + Without a `contig` or `region` all mapped reads in the file +@@ -1206,7 +1206,7 @@ + """perform a :term:`pileup` within a :term:`region`. The region is + specified by :term:`contig`, `start` and `stop` (using + 0-based indexing). :term:`reference` and `end` are also accepted for +- backward compatiblity as synonyms for :term:`contig` and `stop`, ++ backward compatibility as synonyms for :term:`contig` and `stop`, + respectively. Alternatively, a samtools 'region' string + can be supplied. + +@@ -1355,7 +1355,7 @@ + + The region is specified by :term:`contig`, `start` and `stop`. + :term:`reference` and `end` are also accepted for backward +- compatiblity as synonyms for :term:`contig` and `stop`, ++ compatibility as synonyms for :term:`contig` and `stop`, + respectively. Alternatively, a :term:`samtools` :term:`region` + string can be supplied. + +@@ -1459,7 +1459,7 @@ + + The region is specified by :term:`contig`, `start` and `stop`. + :term:`reference` and `end` are also accepted for backward +- compatiblity as synonyms for :term:`contig` and `stop`, ++ compatibility as synonyms for :term:`contig` and `stop`, + respectively. Alternatively, a :term:`samtools` :term:`region` + string can be supplied. The coverage is computed per-base [ACGT]. + +--- python-pysam.orig/pysam/libchtslib.pxd ++++ python-pysam/pysam/libchtslib.pxd +@@ -2502,7 +2502,7 @@ + # 2 if the file is a stream and thus unseekable + # 1 if the file contains an EOF block + # 0 if the file does not contain an EOF block +- # -1 if an error occured whilst reading the file or we could not seek back to where we were ++ # -1 if an error occurred whilst reading the file or we could not seek back to where we were + # + # + int cram_check_EOF(cram_fd *fd) +--- python-pysam.orig/pysam/libchtslib.pyx ++++ python-pysam/pysam/libchtslib.pyx +@@ -587,7 +587,7 @@ + rval = hts_opt_apply(self.htsfile, opts) + if rval != 0: + hts_opt_free(opts) +- raise RuntimeError('An error occured while applying the requested format options') ++ raise RuntimeError('An error occurred while applying the requested format options') + hts_opt_free(opts) + + def parse_region(self, contig=None, start=None, stop=None, +@@ -597,7 +597,7 @@ + either be specified by :term:`contig`, `start` and + `stop`. `start` and `stop` denote 0-based, half-open + intervals. :term:`reference` and `end` are also accepted for +- backward compatiblity as synonyms for :term:`contig` and ++ backward compatibility as synonyms for :term:`contig` and + `stop`, respectively. + + Alternatively, a samtools :term:`region` string can be +--- python-pysam.orig/pysam/libcutils.pyx ++++ python-pysam/pysam/libcutils.pyx +@@ -179,7 +179,7 @@ + `end`. `start` and `end` denote 0-based, half-open intervals. + + :term:`reference` and `end` are also accepted for backward +- compatiblity as synonyms for :term:`contig` and `stop`, ++ compatibility as synonyms for :term:`contig` and `stop`, + respectively. + + Alternatively, a samtools :term:`region` string can be supplied. diff -Nru python-pysam-0.15.1+ds/debian/rules python-pysam-0.15.2+ds/debian/rules --- python-pysam-0.15.1+ds/debian/rules 2018-09-14 08:44:51.000000000 +0000 +++ python-pysam-0.15.2+ds/debian/rules 2019-01-17 09:23:41.000000000 +0000 @@ -25,6 +25,7 @@ override_dh_install: clean-tests dh_install -Xtest.gtf.gz + find debian -name log.txt -delete ifeq (,$(findstring nocheck, $(DEB_BUILD_OPTIONS))) override_dh_auto_test: pysam_data.all cbcf_data.all diff -Nru python-pysam-0.15.1+ds/debian/tests/control python-pysam-0.15.2+ds/debian/tests/control --- python-pysam-0.15.1+ds/debian/tests/control 1970-01-01 00:00:00.000000000 +0000 +++ python-pysam-0.15.2+ds/debian/tests/control 2019-01-17 09:23:41.000000000 +0000 @@ -0,0 +1,7 @@ +Test-Command: make -C tests/pysam_data && make -C tests/cbcf_data && pytest +Depends: @builddeps@, python-pysam +Restrictions: allow-stderr, rw-build-tree + +Test-Command: make -C tests/pysam_data && make -C tests/cbcf_data && pytest-3 +Depends: @builddeps@, python3-pysam, +Restrictions: allow-stderr, rw-build-tree diff -Nru python-pysam-0.15.1+ds/debian/tests/control.autodep8 python-pysam-0.15.2+ds/debian/tests/control.autodep8 --- python-pysam-0.15.1+ds/debian/tests/control.autodep8 2018-07-28 22:37:18.000000000 +0000 +++ python-pysam-0.15.2+ds/debian/tests/control.autodep8 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -Test-Command: make -C tests/pysam_data && make -C tests/cbcf_data && pytest -Depends: @builddeps@, python-pysam -Restrictions: allow-stderr, rw-build-tree - -Test-Command: make -C tests/pysam_data && make -C tests/cbcf_data && pytest-3 -Depends: @builddeps@, python3-pysam, -Restrictions: allow-stderr, rw-build-tree diff -Nru python-pysam-0.15.1+ds/doc/release.rst python-pysam-0.15.2+ds/doc/release.rst --- python-pysam-0.15.1+ds/doc/release.rst 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/doc/release.rst 2019-01-10 22:35:44.000000000 +0000 @@ -7,6 +7,17 @@ Bugfix release. +* [#746] catch pileup itorator out-of-scope segfaults +* [#747] fix faixd fetch with region +* [#748] increase max_pos to (1<<31)-1 +* [#645] Add missing macOS stub files in `MANIFEST.in`, @SoapZA +* [#737] Fix bug in get_aligned_pairs, @bkohrn + +Release 0.15.1 +============== + +Bugfix release. + * [#716] raise ValueError if tid is out of range when writing * [#697] release version using cython 0.28.5 for python 3.7 compatibility diff -Nru python-pysam-0.15.1+ds/MANIFEST.in python-pysam-0.15.2+ds/MANIFEST.in --- python-pysam-0.15.1+ds/MANIFEST.in 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/MANIFEST.in 2019-01-10 22:35:44.000000000 +0000 @@ -50,8 +50,8 @@ include htslib/htslib/*.h include htslib/cram/*.c include htslib/cram/*.h -include htslib/win/*.c -include htslib/win/*.h +include htslib/os/*.c +include htslib/os/*.h include cy_build.py include pysam.py include requirements.txt diff -Nru python-pysam-0.15.1+ds/NEWS python-pysam-0.15.2+ds/NEWS --- python-pysam-0.15.1+ds/NEWS 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/NEWS 2019-01-10 22:35:44.000000000 +0000 @@ -5,6 +5,17 @@ Release notes ============= +Release 0.15.2 +============== + +Bugfix release. + +* [#746] catch pileup itorator out-of-scope segfaults +* [#747] fix faixd fetch with region +* [#748] increase max_pos to (1<<31)-1 +* [#645] Add missing macOS stub files in `MANIFEST.in`, @SoapZA +* [#737] Fix bug in get_aligned_pairs, @bkohrn + Release 0.15.1 ============== diff -Nru python-pysam-0.15.1+ds/pysam/libcalignedsegment.pyx python-pysam-0.15.2+ds/pysam/libcalignedsegment.pyx --- python-pysam-0.15.1+ds/pysam/libcalignedsegment.pyx 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/pysam/libcalignedsegment.pyx 2019-01-10 22:35:44.000000000 +0000 @@ -402,11 +402,18 @@ # use array.tostring() to retrieve byte representation and # save as bytes datafmt = "2sBBI%is" % (len(value) * DATATYPE2FORMAT[typecode][1]) - args.extend([pytag[:2], - ord("B"), - typecode, - len(value), - force_bytes(value.tostring())]) + if IS_PYTHON3: + args.extend([pytag[:2], + ord("B"), + typecode, + len(value), + value.tobytes()]) + else: + args.extend([pytag[:2], + ord("B"), + typecode, + len(value), + force_bytes(value.tostring())]) else: if typecode == 0: @@ -1945,6 +1952,8 @@ else: for i from pos <= i < pos + l: result.append((None, i)) + else: + r_idx += l pos += l elif op == BAM_CHARD_CLIP: @@ -2845,6 +2854,10 @@ # out of sync. for x from 0 <= x < self.n_pu: p = &(self.plp[0][x]) + if p == NULL: + raise ValueError( + "pileup buffer out of sync - most likely use of iterator " + "outside loop") if pileup_base_qual_skip(p, self.min_base_quality): continue pileups.append(makePileupRead(p, self.header)) @@ -2887,8 +2900,15 @@ cdef uint32_t c = 0 cdef uint32_t cnt = 0 cdef bam_pileup1_t * p = NULL + if self.plp == NULL or self.plp[0] == NULL: + raise ValueError("PileupColumn accessed after iterator finished") + for x from 0 <= x < self.n_pu: p = &(self.plp[0][x]) + if p == NULL: + raise ValueError( + "pileup buffer out of sync - most likely use of iterator " + "outside loop") if pileup_base_qual_skip(p, self.min_base_quality): continue cnt += 1 @@ -2956,11 +2976,18 @@ cdef uint8_t rb = 0 cdef uint8_t * buf = self.buf cdef bam_pileup1_t * p = NULL + + if self.plp == NULL or self.plp[0] == NULL: + raise ValueError("PileupColumn accessed after iterator finished") # todo: reference sequence to count matches/mismatches # todo: convert assertions to exceptions for x from 0 <= x < self.n_pu: p = &(self.plp[0][x]) + if p == NULL: + raise ValueError( + "pileup buffer out of sync - most likely use of iterator " + "outside loop") if pileup_base_qual_skip(p, self.min_base_quality): continue # see samtools pileup_seq @@ -3062,6 +3089,11 @@ result = [] for x from 0 <= x < self.n_pu: p = &(self.plp[0][x]) + if p == NULL: + raise ValueError( + "pileup buffer out of sync - most likely use of iterator " + "outside loop") + if p.qpos < p.b.core.l_qseq: c = bam_get_qual(p.b)[p.qpos] else: @@ -3079,11 +3111,19 @@ list: a list of quality scores """ + if self.plp == NULL or self.plp[0] == NULL: + raise ValueError("PileupColumn accessed after iterator finished") + cdef uint32_t x = 0 cdef bam_pileup1_t * p = NULL result = [] for x from 0 <= x < self.n_pu: p = &(self.plp[0][x]) + if p == NULL: + raise ValueError( + "pileup buffer out of sync - most likely use of iterator " + "outside loop") + if pileup_base_qual_skip(p, self.min_base_quality): continue result.append(p.b.core.qual) @@ -3097,12 +3137,19 @@ list: a list of read positions """ + if self.plp == NULL or self.plp[0] == NULL: + raise ValueError("PileupColumn accessed after iterator finished") cdef uint32_t x = 0 cdef bam_pileup1_t * p = NULL result = [] for x from 0 <= x < self.n_pu: p = &(self.plp[0][x]) + if p == NULL: + raise ValueError( + "pileup buffer out of sync - most likely use of iterator " + "outside loop") + if pileup_base_qual_skip(p, self.min_base_quality): continue result.append(p.qpos) @@ -3116,11 +3163,19 @@ list: a list of query names at pileup column position. """ + if self.plp == NULL or self.plp[0] == NULL: + raise ValueError("PileupColumn accessed after iterator finished") + cdef uint32_t x = 0 cdef bam_pileup1_t * p = NULL result = [] for x from 0 <= x < self.n_pu: p = &(self.plp[0][x]) + if p == NULL: + raise ValueError( + "pileup buffer out of sync - most likely use of iterator " + "outside loop") + if pileup_base_qual_skip(p, self.min_base_quality): continue result.append(charptr_to_str(pysam_bam_get_qname(p.b))) diff -Nru python-pysam-0.15.1+ds/pysam/libcalignmentfile.pyx python-pysam-0.15.2+ds/pysam/libcalignmentfile.pyx --- python-pysam-0.15.1+ds/pysam/libcalignmentfile.pyx 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/pysam/libcalignmentfile.pyx 2019-01-10 22:35:44.000000000 +0000 @@ -1,4 +1,3 @@ - # cython: embedsignature=True # cython: profile=True ######################################################## @@ -62,6 +61,8 @@ import array from libc.errno cimport errno, EPIPE from libc.string cimport strcmp, strpbrk, strerror +from libc.stdint cimport INT32_MAX + from cpython cimport array as c_array from cpython.version cimport PY_MAJOR_VERSION @@ -94,7 +95,8 @@ ######################################################## ## global variables # maximum genomic coordinace -cdef int MAX_POS = 2 << 29 +# for some reason, using 'int' causes overlflow +cdef int MAX_POS = (1 << 31) - 1 # valid types for SAM headers VALID_HEADER_TYPES = {"HD" : collections.Mapping, @@ -1314,8 +1316,9 @@ an iterator over genomic positions. """ - cdef int rtid, rstart, rstop, has_coord - + cdef int rtid, has_coord + cdef int32_t rstart, rstop + if not self.is_open: raise ValueError("I/O operation on closed file") @@ -2054,7 +2057,6 @@ IteratorRow.__init__(self, samfile, multiple_iterators=multiple_iterators) - with nogil: self.iter = sam_itr_queryi( self.index, diff -Nru python-pysam-0.15.1+ds/pysam/libcbcf.pyx python-pysam-0.15.2+ds/pysam/libcbcf.pyx --- python-pysam-0.15.1+ds/pysam/libcbcf.pyx 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/pysam/libcbcf.pyx 2019-01-10 22:35:44.000000000 +0000 @@ -111,7 +111,7 @@ ## Constants ######################################################################## -cdef int MAX_POS = 2 << 29 +cdef int MAX_POS = (1 << 31) - 1 cdef tuple VALUE_TYPES = ('Flag', 'Integer', 'Float', 'String') cdef tuple METADATA_TYPES = ('FILTER', 'INFO', 'FORMAT', 'CONTIG', 'STRUCTURED', 'GENERIC') cdef tuple METADATA_LENGTHS = ('FIXED', 'VARIABLE', 'A', 'G', 'R') diff -Nru python-pysam-0.15.1+ds/pysam/libcfaidx.pyx python-pysam-0.15.2+ds/pysam/libcfaidx.pyx --- python-pysam-0.15.1+ds/pysam/libcfaidx.pyx 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/pysam/libcfaidx.pyx 2019-01-10 22:35:44.000000000 +0000 @@ -287,19 +287,20 @@ cdef char *ref cdef int rstart, rend - reference, rstart, rend = parse_region(reference, start, end, region) + contig, rstart, rend = parse_region(reference, start, end, region) - if reference is None: + if contig is None: raise ValueError("no sequence/region supplied.") if rstart == rend: return "" - ref = reference + contig_b = force_bytes(contig) + ref = contig_b with nogil: length = faidx_seq_len(self.fastafile, ref) if length == -1: - raise KeyError("sequence '%s' not present" % reference) + raise KeyError("sequence '%s' not present" % contig) if rstart >= length: return "" @@ -315,7 +316,7 @@ if errno: raise IOError(errno, strerror(errno)) else: - raise ValueError("failure when retrieving sequence on '%s'" % reference) + raise ValueError("failure when retrieving sequence on '%s'" % contig) try: return charptr_to_str(seq) diff -Nru python-pysam-0.15.1+ds/pysam/libchtslib.pyx python-pysam-0.15.2+ds/pysam/libchtslib.pyx --- python-pysam-0.15.1+ds/pysam/libchtslib.pyx 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/pysam/libchtslib.pyx 2019-01-10 22:35:44.000000000 +0000 @@ -9,10 +9,9 @@ from posix.unistd cimport dup from libc.errno cimport errno +from libc.stdint cimport INT32_MAX from cpython cimport PyBytes_FromStringAndSize - from pysam.libchtslib cimport * - from pysam.libcutils cimport force_bytes, force_str, charptr_to_str, charptr_to_str_w_len from pysam.libcutils cimport encode_filename, from_string_and_size @@ -25,7 +24,7 @@ import os import io import re -from warnings import warn +from warnings import warn ######################################################################## @@ -41,7 +40,7 @@ DEF SEEK_END = 2 # maximum genomic coordinace -cdef int MAX_POS = 2 << 29 +cdef int MAX_POS = (1 << 31) - 1 cdef tuple FORMAT_CATEGORIES = ('UNKNOWN', 'ALIGNMENTS', 'VARIANTS', 'INDEX', 'REGIONS') cdef tuple FORMATS = ('UNKNOWN', 'BINARY_FORMAT', 'TEXT_FORMAT', 'SAM', 'BAM', 'BAI', 'CRAM', 'CRAI', @@ -630,8 +629,8 @@ """ cdef int rtid - cdef long long rstart - cdef long long rstop + cdef int32_t rstart + cdef int32_t rstop if reference is not None: if contig is not None: @@ -644,7 +643,7 @@ stop = end if contig is None and tid is None and region is None: - return 0, 0, 0, 0 + return 0, 0, 0, MAX_POS rtid = -1 rstart = 0 diff -Nru python-pysam-0.15.1+ds/pysam/libcutils.pyx python-pysam-0.15.2+ds/pysam/libcutils.pyx --- python-pysam-0.15.1+ds/pysam/libcutils.pyx 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/pysam/libcutils.pyx 2019-01-10 22:35:44.000000000 +0000 @@ -12,6 +12,7 @@ from cpython cimport array as c_array from libc.stdlib cimport calloc, free from libc.string cimport strncpy +from libc.stdint cimport INT32_MAX, int32_t from libc.stdio cimport fprintf, stderr, fflush from libc.stdio cimport stdout as c_stdout from posix.fcntl cimport open as c_open, O_WRONLY @@ -24,7 +25,7 @@ ##################################################################### # hard-coded constants -cdef int MAX_POS = 2 << 29 +cdef int MAX_POS = (1 << 31) - 1 ################################################################# # Utility functions for quality string conversions @@ -48,7 +49,10 @@ for x from 0 <= x < len(qualities): result[x] = qualities[x] + offset - return force_str(result.tostring()) + if IS_PYTHON3: + return force_str(result.tobytes()) + else: + return result.tostring() cpdef qualities_to_qualitystring(qualities, int offset=33): @@ -198,51 +202,58 @@ for invalid or out of bounds regions. """ - cdef long long rstart - cdef long long rend + cdef int32_t rstart + cdef int32_t rstop - if contig is not None: - reference = contig - if stop is not None: - end = stop + + if reference is not None: + if contig is not None: + raise ValueError('contig and reference should not both be specified') + contig = reference + + if contig is not None and region is not None: + raise ValueError('contig/reference and region should not both be specified') + + if end is not None: + if stop is not None: + raise ValueError('stop and end should not both be specified') + stop = end + + if contig is None and region is None: + raise ValueError("neither contig nor region are given") rstart = 0 - rend = MAX_POS - if start != None: + rstop = MAX_POS + if start is not None: try: rstart = start except OverflowError: raise ValueError('start out of range (%i)' % start) - if end != None: + if stop is not None: try: - rend = end + rstop = stop except OverflowError: - raise ValueError('end out of range (%i)' % end) + raise ValueError('stop out of range (%i)' % stop) if region: - region = force_str(region) if ":" in region: contig, coord = region.split(":") parts = coord.split("-") rstart = int(parts[0]) - 1 if len(parts) >= 1: - rend = int(parts[1]) + rstop = int(parts[1]) else: contig = region - if not reference: - return None, 0, 0 - + if rstart > rstop: + raise ValueError('invalid coordinates: start (%i) > stop (%i)' % (rstart, rstop)) if not 0 <= rstart < MAX_POS: raise ValueError('start out of range (%i)' % rstart) - if not 0 <= rend <= MAX_POS: - raise ValueError('end out of range (%i)' % rend) - if rstart > rend: - raise ValueError( - 'invalid region: start (%i) > end (%i)' % (rstart, rend)) + if not 0 <= rstop <= MAX_POS: + raise ValueError('stop out of range (%i)' % rstop) - return force_bytes(reference), rstart, rend + return contig, rstart, rstop def _pysam_dispatch(collection, diff -Nru python-pysam-0.15.1+ds/pysam/version.py python-pysam-0.15.2+ds/pysam/version.py --- python-pysam-0.15.1+ds/pysam/version.py 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/pysam/version.py 2019-01-10 22:35:44.000000000 +0000 @@ -1,5 +1,5 @@ # pysam versioning information -__version__ = "0.15.0" +__version__ = "0.15.2" # TODO: upgrade number __samtools_version__ = "1.9" diff -Nru python-pysam-0.15.1+ds/tests/AlignedSegment_test.py python-pysam-0.15.2+ds/tests/AlignedSegment_test.py --- python-pysam-0.15.1+ds/tests/AlignedSegment_test.py 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/tests/AlignedSegment_test.py 2019-01-10 22:35:44.000000000 +0000 @@ -430,6 +430,35 @@ (6, 27), (7, 28), (8, 29), (9, 30)]) + def test_equivalence_matches_only_and_with_seq(self): + a = self.build_read() + a.query_sequence = "ACGT" * 2 + a.cigarstring = "4M1D4M" + a.set_tag("MD", "4^x4") + full = (list(zip(range(0, 4), range(20, 24), "ACGT")) + + [(None, 24, "x")] + + list(zip(range(4, 8), range(25, 29), "ACGT"))) + self.assertEqual( + a.get_aligned_pairs(matches_only=False, with_seq=True), full) + + self.assertEqual( + a.get_aligned_pairs(matches_only=True, with_seq=True), + [x for x in full if x[0] is not None and x[1] is not None]) + + a = self.build_read() + a.query_sequence = "ACGT" * 2 + a.cigarstring = "4M1N4M" + a.set_tag("MD", "8") + full = (list(zip(range(0, 4), range(20, 24), "ACGT")) + + [(None, 24, None)] + + list(zip(range(4, 8), range(25, 29), "ACGT"))) + self.assertEqual( + a.get_aligned_pairs(matches_only=False, with_seq=True), full) + + self.assertEqual( + a.get_aligned_pairs(matches_only=True, with_seq=True), + [x for x in full if x[0] is not None and x[1] is not None]) + def test_get_aligned_pairs_lowercase_md(self): a = self.build_read() a.query_sequence = "A" * 10 diff -Nru python-pysam-0.15.1+ds/tests/AlignmentFileHeader_test.py python-pysam-0.15.2+ds/tests/AlignmentFileHeader_test.py --- python-pysam-0.15.1+ds/tests/AlignmentFileHeader_test.py 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/tests/AlignmentFileHeader_test.py 2019-01-10 22:35:44.000000000 +0000 @@ -121,6 +121,7 @@ self.compare_headers(header, self.header_without_text) self.check_name_mapping(header) + class TestHeaderSAM(unittest.TestCase): """testing header manipulation""" @@ -287,6 +288,7 @@ def check_read_write(self, flag_write, header): fn = get_temp_filename() + print(fn) with pysam.AlignmentFile( fn, flag_write, @@ -299,17 +301,30 @@ with pysam.AlignmentFile(fn) as inf: read_header = inf.header - os.unlink(fn) + # os.unlink(fn) self.compare_headers(header, read_header) + expected_lengths = dict([(x["SN"], x["LN"]) for x in header["SQ"]]) + self.assertEqual(expected_lengths, + dict(zip(read_header.references, + read_header.lengths))) def test_SAM(self): self.check_read_write("wh", self.header) def test_BAM(self): self.check_read_write("wb", self.header) - + def test_CRAM(self): header = copy.copy(self.header) - # for CRAM, \t needs to be quoted: - header['PG'][1]['CL'] = re.sub(r"\t", r"\\\\t", header['PG'][1]['CL']) + if "PG" in header: + # for CRAM, \t needs to be quoted: + header['PG'][1]['CL'] = re.sub(r"\t", r"\\\\t", header['PG'][1]['CL']) self.check_read_write("wc", header) + + +class TestHeaderLargeContigs(TestHeaderWriteRead): + """see issue 741""" + + header = {'SQ': [{'LN': 2147483647, 'SN': 'chr1'}, + {'LN': 1584, 'SN': 'chr2'}], + 'HD': {'VN': '1.0'}} diff -Nru python-pysam-0.15.1+ds/tests/AlignmentFilePileup_test.py python-pysam-0.15.2+ds/tests/AlignmentFilePileup_test.py --- python-pysam-0.15.1+ds/tests/AlignmentFilePileup_test.py 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/tests/AlignmentFilePileup_test.py 2019-01-10 22:35:44.000000000 +0000 @@ -115,7 +115,7 @@ fastafile=self.fastafile, redo_baq=True) self.check_equal(refs, iterator) - + class TestPileupReadSelectionFastafile(TestPileupReadSelection): '''test pileup functionality - backwards compatibility''' @@ -206,10 +206,19 @@ '''test if exception is raised if pileup col is accessed after iterator is exhausted.''' + max_n = 0 for pileupcol in self.samfile.pileup(): - pass - - self.assertRaises(ValueError, getattr, pileupcol, "pileups") + if max_n < pileupcol.n: + max_col = pileupcol + max_n = pileupcol.n + + self.assertRaises(ValueError, getattr, max_col, "pileups") + self.assertRaises(ValueError, max_col.get_query_sequences) + self.assertRaises(ValueError, max_col.get_num_aligned) + self.assertRaises(ValueError, max_col.get_query_qualities) + self.assertRaises(ValueError, max_col.get_mapping_qualities) + self.assertRaises(ValueError, max_col.get_query_positions) + self.assertRaises(ValueError, max_col.get_query_names) class TestIteratorColumnBAM(unittest.TestCase): diff -Nru python-pysam-0.15.1+ds/tests/faidx_test.py python-pysam-0.15.2+ds/tests/faidx_test.py --- python-pysam-0.15.1+ds/tests/faidx_test.py 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/tests/faidx_test.py 2019-01-10 22:35:44.000000000 +0000 @@ -45,6 +45,13 @@ self.assertRaises(ValueError, self.file.fetch, "chr1", 20, 10) self.assertRaises(KeyError, self.file.fetch, "chr3", 0, 100) + def test_fetch_with_region_and_contig_raises_exception(self): + self.assertRaises(ValueError, self.file.fetch, "chr1", 10, 20, "chr1:11-20") + + def test_fetch_with_region_is_equivalent(self): + self.assertEqual(self.file.fetch("chr1", 10, 20), + self.file.fetch(region="chr1:11-20")) + def testLength(self): self.assertEqual(len(self.file), 2) @@ -60,7 +67,7 @@ filename = os.path.join(BAM_DATADIR, "ex1.fa") data_suffix = ".fa" - + def test_raise_exception_if_index_is_missing(self): self.assertRaises(IOError, pysam.FastaFile, @@ -223,22 +230,28 @@ if not check_url(self.url): return - with pysam.Fastafile(self.url) as f: - self.assertEqual( - len(f.fetch("chr1", 0, 1000)), - 1000) - + try: + with pysam.Fastafile(self.url) as f: + self.assertEqual( + len(f.fetch("chr1", 0, 1000)), + 1000) + except (OSError, IOError): + pass + def test_sequence_lengths_are_available(self): if not check_url(self.url): return - with pysam.Fastafile(self.url) as f: - self.assertEqual(len(f.references), 3366) - self.assertTrue("chr1" in f.references) - self.assertEqual(f.lengths[0], - 248956422) - self.assertEqual(f.get_reference_length("chr1"), - 248956422) + try: + with pysam.Fastafile(self.url) as f: + self.assertEqual(len(f.references), 3366) + self.assertTrue("chr1" in f.references) + self.assertEqual(f.lengths[0], + 248956422) + self.assertEqual(f.get_reference_length("chr1"), + 248956422) + except (OSError, IOError): + pass class TestFastqRecord(unittest.TestCase): diff -Nru python-pysam-0.15.1+ds/.travis.yml python-pysam-0.15.2+ds/.travis.yml --- python-pysam-0.15.1+ds/.travis.yml 2018-09-13 20:15:05.000000000 +0000 +++ python-pysam-0.15.2+ds/.travis.yml 2019-01-10 22:35:44.000000000 +0000 @@ -3,7 +3,6 @@ - osx language: c -sudo: false env: matrix: