Skip to content

6.0.0

Latest

Choose a tag to compare

@tfenne tfenne released this 26 Oct 19:11
· 1 commit to master since this release
0d106fb

htsjdk 6.0.0 Release Notes

Major release. It includes every change in 5.0.2. Before upgrading, read Upgrading from 5.x; to explain differences from files 5.x wrote, see Output that differs from 5.x.

Headlines

  • java.nio.file.Path throughout the public API. Every reader, writer, index and reference works with any NIO file system provider (S3, GCS, HDFS, jimfs), and String and URI arguments are resolved by their scheme.
  • Current VCF and BCF. VCF 3.2 to 4.5 are read and 4.0 to 4.5 written, with VCF 4.4 and 4.5's additions. BCF 2.1 and 2.2 are read, raw or BGZF, and BCF is written as bcftools writes it, BGZF BCF 2.2 with a CSI index.
  • CSI indexes, and CRAM's own CRAI. BAM, bgzipped VCF and other tabix files, and BCF can be indexed with CSI, for references longer than 512 Mbp. CRAM is indexed with a .crai and queried from it directly.
  • Bgzipped SAM is an indexed format, written, indexed and queried like BAM.
  • Faster than 5.0.2. Converting BAM to CRAM takes 29% less time, reading VCF 9–11% less, and writing bgzipped VCF 12% less. The CRAM 3.1 profiles choose codecs as htslib does.

Upgrading from 5.x

These changes can break code that compiles or runs against 5.x.

Paths and files

  • java.io.File APIs are replaced by java.nio.file.Path (224 methods and constructors). Pass a Path, or a String or URI, which IOUtil.getPath resolves by scheme; bridge a File with file.toPath() or the null-safe IOUtil.toPath(file).

    SamReader r = SamReaderFactory.makeDefault().open(Path.of("/data/x.bam"));
    SAMFileWriter w = new SAMFileWriterFactory().makeBAMWriter(header, true, Path.of("/data/out.bam"));
    SamReader s3 = SamReaderFactory.makeDefault().open(URI.create("s3://bucket/x.bam")); // with an S3 provider on the class path
  • A few File APIs remain: temporary files (IOUtil.newTempFile, getDefaultTmpDir, createTempDir), the bridges IOUtil.toPath and filesToPaths, and sixteen deprecated overloads, each with a Path twin, in CRAMFileReader, MetricsFile, BlockCompressedInputStream and CRAIIndex.

  • Defaults.REFERENCE_FASTA is a Path.

  • ReferenceSequenceFile.close() no longer declares IOException (#1179): delete catch blocks that only it needed, and throws IOException from implementations of close().

  • Removed: NotPrimarySkippingIterator, deprecated since 2.13.0 (use SecondaryAlignmentSkippingIterator), and TestUtil.BASE_URL_FOR_HTTP_TESTS.

SAM, BAM and CRAM

  • A CRAM writer refuses codecs its CRAM version lacks, where 5.x wrote a file labelled 3.0 full of 3.1 codecs. A default strategy asked for CRAM 3.0 takes the new NORMAL_3_0 profile's codecs; SMALL, ARCHIVE and codecs set by hand are refused for 3.0. setCramVersion accepts only 3.0 and 3.1.
  • SAMFileWriterFactory writes x.sam.gz as bgzipped SAM, where it wrote BAM, and recognises names in any case: x.SAM and x.CRAM are SAM and CRAM, not BAM, and x.BAM's index is x.bai.
  • Header text is UTF-8, and read names and tags pass through byte for byte, in SAM, BAM and CRAM alike (#1108, #1202, #1940). UTF-8 is what the SAM specification allows in DS, CL and @CO values; read names and Z and A tags are passed through unchanged, as htslib passes them, rather than checked against the specification's ASCII-only rule, which htsjdk doesn't enforce elsewhere in the header either. Writing a tab, line break or NUL a field can't hold, or a char above 0xFF in a read name or tag, throws IllegalArgumentException. A header line that isn't valid UTF-8, as 5.x could write, is read as Latin-1 and written back as UTF-8, and a non-ASCII read name in a CRAM from 5.x reads back as its UTF-8 bytes.
  • Records the specification allows on unmapped and unpaired reads are accepted (#1584): RNAME * with a MAPQ or CIGAR, and MAPQ 255 on an unmapped read. Pair and mate flags on an unpaired read, and other MAPQs on an unmapped read, are warnings, among them the new INVALID_UNPAIRED_FLAG_MATE_UNMAPPED and INVALID_UNMAPPED_MAPPING_QUALITY; STRICT still rejects them.
  • SAMSequenceRecord accepts names outside the SAM RNAME pattern (#1295), except an empty name, *, =, and names with spaces or control characters. In a SAM or BAM header such a name is the new INVALID_SEQUENCE_NAME error. Check names with validateSequenceName or isValidSequenceName.
  • A read group's DT is kept as written (#561), not rewritten in the JVM's time zone, which changes SAMUtils.calculateReadGroupRecordChecksum for such headers. An unparseable DT is a warning, and getRunDate() returns null for it.

VCF and BCF

  • BCF is written as BGZF BCF 2.2 with a .csi index. VariantContextWriterBuilder.setBCFVersion(BCFVersion.BCF_2_1) writes raw BCF 2.1 with a Tribble .idx, as 5.x did; only raw BCF accepts a custom IndexCreator.
  • Writing records out of order with on-the-fly indexing throws (#787). INDEX_ON_THE_FLY is a default option, so this applies to any VCF or BCF written to a file with a reference dictionary: sort the records, or unset the option.
  • VCF and BCF are recognised by one rule (#664): .vcf, .gvcf and .bcf, and .vcf or .gvcf followed by .gz, .gzip, .bgz or .bgzf, in any case. VariantContextWriterBuilder throws for x.gz, x.txt.gz and x.bcf.gz, which 5.x wrote as BGZF VCF; call setOutputFileType after setOutputPath to write any format under any name.
  • Header and sample collections are unmodifiable: VCFHeader's accessors, and getSampleNames() and getSampleNamesOrderedByName() on VariantContext and GenotypesContext; copy before changing. getSampleNamesInOrder() and getSampleNameToOffset() return List and Map, not ArrayList and HashMap.
  • A header keeps the first INFO, FORMAT, FILTER or structured line per ID (#250, #929), as bcftools does, and numbers its contig lines itself (#1573).
  • A standard INFO or FORMAT line declared with another type is kept as declared (GQ as Float, for example), so VCFUtils.smartMergeHeaders refuses a key declared with two types; fix such a header first, for example with VCFStandardHeaderLines.getInfoLine("DB"). The standard PQ line is Integer (#751).
  • A header keeps the version it declares through copies and merges, and null if it declares none. Writers write the version given to setVCFVersion, else the header's (at least 4.2), and refuse a header line that needs a later one. VCFHeader.validateVersionTransition is gone.
  • A record's end is worked out as htslib works it out, from REF, END, SVLEN (for <DEL>, <DUP>, <CNV> and <INV>) and LEN, so getEnd() changes for symbolic alleles with an SVLEN and no END.
  • A genotype keeps each allele's phase (0/1|2, and VCF 4.4's leading |0/1). Writing a phase the output version can't express throws; VCFEncoder.writeGtField has an overload that allows it.
  • BCF2Type's integer ranges leave the sentinel values unused, as htslib does: −127..−121 are written as INT16, the seven values above Integer.MIN_VALUE are refused, and an INT8 −127, INT16 −32767 or INT32 −2147483647 in a BCF from an earlier htsjdk reads as the end of its vector.
  • VCF, GFF3 and Tribble text are read and written as UTF-8, not Latin-1 or the platform default: a byte in a Latin-1 file that isn't valid UTF-8 reads as U+FFFD and is lost on rewrite.
  • The samjdk.optimistic_vcf_4_4 property and Defaults.OPTIMISTIC_VCF_4_4 and OPTIMISTIC_VCF_4_4_PROPERTY are removed. VCF3Codec no longer takes part in codec discovery.
  • StructuralVariantType gains MIXED, which VariantContext.getStructuralVariantType() returns when the alleles have more than one major type or disagree with SVTYPE.
  • VCFCompoundHeaderLine.equals compares Source and Version. Header attribute values are escaped when written, so a caller that escaped quotes itself must stop.
  • For AbstractVCFCodec subclasses: parseFilters takes the line number, the scratch fields (parts, genotypeParts, alleleMap, lineNo, filterHash) are gone, and stringCache is private (use getCachedString).

Indexes

  • An indexed CRAM is written with a .crai, not a .cram.bai. SamFiles.findIndex finds either; SAMFileWriterFactory.setCreateBaiIndexForCram(true) writes a BAI for one more release.

  • A reader's index is no longer a DiskBasedBAMFileIndex, CSIIndex or AbstractBAMFileIndex, so casts to them fail. Ask SamReader.Indexing.getHtsIndex instead: getHtsIndex(BrowseableBAMIndex.class) for bins, getHtsIndex(BAMIndex.class) for per-reference counts, getHtsIndex(CRAIQueryIndex.class) for CRAM containers. getIndex() is deprecated. A CRAI keeps no counts, so getUnplacedRecordCount() is empty for a CRAM with unplaced reads.

    // 5.x: ((AbstractBAMFileIndex) reader.indexing().getIndex()).getNoCoordinateCount()
    OptionalLong unplaced = reader.indexing().getHtsIndex().getUnplacedRecordCount();
  • The deprecated BAM index classes still work when constructed directly, but a query that finds nothing returns an empty span, not null, their memory-mapping arguments do nothing, and AbstractBAMFileIndex's protected methods for reading the file are gone. BAMIndexMerger rejects a CSI.

  • TabixIndex is built on the new BinningIndex: TabixIndex(TabixFormat, List<String>, BinningIndex) and getBinningIndex() replace the BinningIndexContent[] constructor and getIndices(), and the internal index types of TabixReader and TabixUtils are gone.

  • A .csi beside a tabix-indexed file is preferred to a .tbi, as htslib prefers it.

  • A Tribble index can't be built over BGZF BCF (#945), where 5.x built one that found nothing; BCF2Codec refuses a compressed stream. Index BGZF BCF with CSI.

  • AbstractFeatureReader.getFeatureReader(resource, codec, Index) refuses a TabixIndex or BCFCsiIndex, whose BGZF offsets it would misread; give it the index's path instead.

  • Tribble iterators close when read to their end, and closing a reader closes any still open (#494). A query whose start is after its end returns nothing from a Tribble .idx (#204).

Other

  • DiskBackedQueue and SamRecordTrackingBuffer are AutoCloseable, and no longer delete their spill files when garbage-collected: close or clear them.
  • Runtime dependencies are updated: commons-compress 1.28.0, which brings in commons-codec, xz 1.12, snappy-java 1.1.10.8, org.json 20260522, and commons-logging 1.4.0 for JEXL.
  • VCF objects stored with Java serialization by 5.x, such as a VCFHeader, its header lines or genotypes, can't be deserialized by 6.0 (InvalidClassException), since their classes changed. This concerns serialized Java objects only; VCF and BCF files written by 5.x read as before.
  • Some public classes inside the CRAM and BCF codecs changed signatures: TrialCompressor's constructor, CompressionUtils.encodePack, and the constructors of BCF2FieldEncoder's subclasses.

Output that differs from 5.x

What htsjdk writes, for anyone comparing output with files 5.x wrote (expected test outputs, for example). Each is a fix or a change described elsewhere in this section.

  • VCF header: only the first line per ID is kept; a standard line declared with another type stays as declared; ##contig lines carry md5, URL and species from a sequence dictionary (#730); ##fileformat is the header's version (at least 4.2), where a copy of a 4.3 header used to be written as 4.2; INFO and FORMAT lines keep every attribute, and quoted values are escaped as the specification requires; repeated unstructured lines, and structured lines with distinct IDs, are kept (#500, #277).
  • VCF records: negative doubles are written like positive ones (-5.00, not -5.000e+00); a missing GT is written as ., where 5.x threw, and a sample with every value missing as ., not an empty column; String values are percent-encoded from VCF 4.3; 0/1|2 is written as it is, not as 0|1|2.
  • BCF: BGZF BCF 2.2 with a .csi; IDX= on FILTER, INFO, FORMAT and contig lines; vectors sized from their values and padded with END_OF_VECTOR; flags, GT width, phase bits and rlen as htslib writes them.
  • CRAM: a .crai, not a .cram.bai; M5 added to @SQ lines without one (#506); the file id is the file name, so the same records give identical files wherever they are written (#1068); empty blocks written RAW (#1633); reads without bases, unsigned B arrays and pairs with linked template lengths stored as htslib stores them; different codec choices (see Performance).
  • SAM and BAM: header text is UTF-8; @RG DT is as written; a CIGAR too long for BAM goes in CG:B:I, not CG:B:i (#1560); a U in SEQ is read and written as T (#1728); x.sam.gz is bgzipped SAM.
  • Indexes: BAI, TBI and CSI have htslib's content and equal samtools' and tabix's once read (a CSI for bgzipped SAM also carries a tabix header); a TBI carries record counts as tabix's does (#1586); a CRAM's BAI has real offsets in its metadata (#401).
  • Elsewhere: FastaReferenceWriter's .fai gives a sequence shorter than one line its own line widths, as samtools does; the .md5 beside a gzipped file is of the compressed file (#758); BasicFastqWriter ends lines with \n on every platform (#1105); warnings go through Log (#1261).

New features

VCF and BCF versions

Read Written
VCF 3.2 to 4.5, by default 4.0 to 4.5: the version given to setVCFVersion, else the header's, at least 4.2
BCF 2.1 and 2.2, raw or BGZF BGZF BCF 2.2 by default; raw BCF 2.1 with setBCFVersion(BCFVersion.BCF_2_1)

VCF 4.4 and 4.5 bring the Number codes P, LA, LR, LG and M; a phase for each allele, including a leading |0/1 (Genotype.isAllelePhased); reserved keys, as constants in the new VCFConstants.INFO and VCFConstants.FORMAT, and as lines in VCFStandardHeaderLines where a key's definition doesn't vary by version; symbolic and breakend alleles, parsed into StructuralVariantAllele and Breakend; and record ends from SVLEN and LEN. String values are percent-encoded from VCF 4.3, and text is UTF-8.

BCF is read as htslib reads it, from its dictionaries (sparse IDX values included) to its end-of-vector markers, and decodes to the values the VCF reader gives (#946). BCF2Writer is public. The VCF and BCF codecs are thread-safe once their header is read (#1026).

Indexing

Format Index written Indexes read
BAM BAI by default, or CSI BAI, CSI
CRAM CRAI CRAI, BAI
Bgzipped SAM CSI by default, or BAI BAI and CSI from samtools index; TBI and CSI from tabix
Bgzipped VCF, BED, GFF TBI by default, or CSI TBI, CSI
BCF CSI for BGZF BCF; Tribble .idx for raw BCF 2.1 CSI, .idx
  • Choose the index with SAMFileWriterFactory.setBamIndexType or setSamIndexType (BAI, CSI, or AUTO, a CSI only when a sequence is too long for a BAI) and VariantContextWriterBuilder.setTabixIndexType (TBI or CSI).
  • Index an existing file with BAMIndexer.createIndex(reader, output, log, indexType) for BAM and bgzipped SAM, and IndexFactory.createIndex(path, codec, type, dictionary) for bgzipped text (IndexType.TABIX or CSI) and BGZF BCF (CSI, for a BCF whose contigs are in the header's order).
  • References longer than 512 Mbp need CSI, or CRAI for CRAM.
  • Indexes match htslib's: equal to samtools' and tabix's once read, with the record counts bcftools index -n reads, which TabixIndex.getRecordCount gives too (#1586).

Every index answers queries through one format-neutral interface, htsjdk.index.HtsQueryIndex, which SamReader.Indexing.getHtsIndex() returns; getHtsIndex(Class) reaches what one format alone has. A CRAM is queried from its CRAI directly (#851), so a CRAM on a reference longer than 512 Mbp is queryable (#1747) and opening one is about 70% faster. BGZF BCF is queried through its CSI by the new BCFFileReader, which VCFFileReader uses.

BAI and CSI indexes are read a reference at a time when a query first needs them, and kept while memory allows: 1,000 queries on one chromosome of a whole-genome BAI take 2 ms rather than 64, and through a CSI 11 ms rather than 932. SamReaderFactory.indexLoading chooses LAZY, EAGER or AUTO, the default, which reads an index whole when it is given as a stream, is on another file system, or is under a megabyte. BAI, TBI and CSI share one sparse implementation, htsjdk.index.BinningIndex, so an index over 50,000 small contigs takes 10 MB rather than 951 MB, and queries through a tabix index are faster (VCFFileReader.query −20%).

Bgzipped SAM

x.sam.gz (or .gzip, .bgz or .bgzf) is now an indexed format, like BAM:

  • SAMFileWriterFactory writes it, and indexes it while writing: a CSI by default (x.sam.gz.csi, as samtools writes), or a BAI with setSamIndexType.
  • A file opened from a Path is queried like a BAM, through the BAI or CSI of samtools index or the TBI or CSI of tabix -p sam.
  • An existing file is indexed with BAMIndexer.createIndex, from a reader opened with INCLUDE_SOURCE_IN_RECORDS.

Other new features

  • SAMRecordQueryNameNaturalComparator sorts read names in samtools' natural order (SS:queryname:natural).
  • The NORMAL_3_0 CRAM profile writes CRAM 3.0 with rANS 4x8 and GZIP, which htsjdk before 4.3.0 and other readers without CRAM 3.1 support read.
  • CRAMContainerStreamWriter.finish(writeEOFContainer, closeStream) lets a caller keep its stream open (#1092).
  • INFO and FORMAT header lines keep every attribute, in any order, through getGenericFieldValue and getGenericFields; smartMergeHeaders keeps the line with the later Version when two inputs define a field alike for the same Source.
  • VariantFileType tells VCF from BCF by name or by content; VariantContext.getIDs(); VCFHeader.getOtherHeaderLines(String).
  • IOUtil.openGzipOrBgzfStream reads BGZF, and gzip of any number of members, from any stream.
  • htsjdk.samtools.util.UnsynchronizedByteArrayOutputStream, a ByteArrayOutputStream without locking.
  • The jar names its automatic module htsjdk (#1724), so a modular application can requires htsjdk;; it is not yet an explicit module, so jlink can't use it.

Deprecations

  • VCFConstants' top-level INFO and FORMAT key names (GENOTYPE_KEY, DEPTH_KEY and the rest), in favour of VCFConstants.INFO and VCFConstants.FORMAT; each one's Javadoc names its replacement. They remain compile-time constants, so only builds that treat deprecation warnings as errors notice.
  • For removal in 7.0.0: SamReader.Indexing.getIndex(); SAMFileWriterFactory.setCreateBaiIndexForCram; DiskBasedBAMFileIndex, CSIIndex, AbstractBAMFileIndex, BinningIndexBuilder, BinningIndexContent, LinearIndex, BinWithOffset, and BAMIndexMerger.mergeBins and mergeLinearIndexes; and SamIndexes.openIndexFileAsBaiOrNull, openIndexUrlAsBaiOrNull, asBaiStreamOrNull and asBaiSeekableStreamOrNull (#1425).
  • SamReaderFactory.Option.CACHE_FILE_BASED_INDEXES and DONT_MEMORY_MAP_INDEX, which have no effect.
  • The sixteen File overloads that remain (see Paths and files).
  • AsciiLineReader and AsciiLineReaderIterator, in favour of Utf8LineReader and Utf8LineReaderIterator.
  • VCF3Codec; VCFFileReader.isBCF, AbstractVCFCodec.canDecodeFile and BCF2Codec.tryReadBCFVersion, in favour of VariantFileType; BCF2Codec.ALLOWED_MINOR_VERSION, ALLOWED_BCF_VERSION, validateVersionCompatibility and error(String).
  • VariantContextUtils.getMetaDataForField, in favour of VCFHeader.getInfoHeaderLine and getFormatHeaderLine.

Performance

Against 5.0.2, each run in a fresh JVM, with BGZF level 1 and the NORMAL CRAM profile, on chromosome 3 of a 1000 Genomes WGS BAM (1.37 million reads), a 1,000-sample VCF and a one-million-record gVCF:

Change
BAM to CRAM −29%
CRAM to BAM −7%
Reading VCF −9% to −11%
VCF to bgzipped VCF −12%
VCF to BCF 2.1 −17%
Reading BAM, BAM to BAM, BCF to VCF unchanged
  • The CRAM 3.1 profiles try the codecs htslib's do, and choose among them as htslib does. NORMAL's files are 0.7–1.1% larger than samtools'; SMALL's and ARCHIVE's are 2–9% smaller than before but take longer to write. A CRAM 3.1 writer no longer holds 6 MB of rANS tables for every distinct tag.
  • SAM text is parsed about 2.2 times as fast; writing it is about 4.5% slower for reads with long Z tags such as OQ, for the checks that keep its text valid.
  • BCF writing takes genotypes by position and encodes without a lock per byte; decoding skips padding. BAM bases are packed through a lookup table. Index queries: see Indexing.
  • SamLocusIterator and EdgeReadIterator no longer slow down as reads get longer (#1490).

Bug fixes

Fixes that change output are listed under Output that differs from 5.x.

SAM, BAM and CRAM

  • A mapped read without bases (SEQ *) keeps its CIGAR, NM and MD through a CRAM htsjdk writes; 5.x read it back as 0M.
  • htsjdk 4.x can read the CRAMs htsjdk writes again, so far as it reads their CRAM version: 5.0.0 wrote empty GZIP blocks that 4.x rejects (#1633).
  • A CRAM labelled 3.0 no longer contains CRAM 3.1 codecs: the FAST profile compressed tags with rANS Nx16.
  • CRAM template lengths of mates stored together are derived as htslib derives them (#1189).
  • Unsigned B arrays keep their type through CRAM (#499), and bytes 0x80–0xFF in CRAM read names and tags are kept.
  • The NM worked out for a CRAM record counts every inserted base (#1187); a read running past the end of its reference keeps its bases, NM and MD.
  • Reading CRAM matches samtools in MD past the end of the reference, the internal cF tag, and the PNEXT of an unpaired read.
  • The CRAM writer keeps an unpaired read's 0x2, 0x8, 0x20, 0x40 and 0x80 flags and its PNEXT, and an RG tag with no @RG line. Such unpaired reads now fail STRICT validation when read from CRAM, as they do from SAM and BAM.
  • The CRAM writer handles an empty quality array as missing qualities, and a slice whose placed reads are all unmapped (#714).
  • A CRAM with an EOF container partway through is read to its end (#1271).
  • CRAM quality scores with a HUFFMAN encoding can be read (#518).
  • CRAM iterators over a seekable stream no longer cut each other short (#563).
  • A CRAM opened by Path is read through a buffer; unbuffered, it was very slow on NFS (#1756).
  • ReferenceSource no longer returns another contig's bases when one source serves CRAMs whose @SQ lines are in different orders.
  • CRAMFileReader constructors without a validation stringency use SILENT.
  • The beta API's CRAM 3.0 encoder writes CRAM 3.0, and its 2.1 encoder throws.
  • Multi-interval queries return every record when a file's references are not in dictionary order (#1271).
  • queryUnmapped() on a CSI-indexed BAM no longer seeks to the wrong place.
  • A BAM writer that can't build or write its index fails the write, and refuses later writes.
  • Reading a BAI or TBI whose metadata bin has the wrong number of chunks suggests a CSI index, since the reference is probably longer than 2^29 (#823, #643).
  • A sort-order check no longer fails because the caller changed a record it was given (#760).
  • SamReaderFactory.makeDefault() uses the default inflater factory in force when it is called (#1666, #831).
  • A plain SAM file can be iterated again after its first iterator is closed (#681).
  • A reader whose header can't be read no longer leaks its file handle (#494).
  • SAMFileWriterFactory's copies keep the deflater factory and the flag format.
  • SAMRecord.isUnsignedArrayAttribute no longer throws NullPointerException.
  • SAMUtils.getNumOverlappingAlignedBasesToClip and clipOverlappingAlignedBases clip part of a partly overlapping = or X element, as they do M (5.x clipped 150= to 150S where 50=100S was right), and no longer clip mates on different references.
  • A SAMFileWriter given records out of order names the record before the offending one, rather than the offending one twice.
  • Bgzipped SAM is read with the InflaterFactory set on SamReaderFactory, rather than always the default.
  • A CRAM reader on a stream that can't seek throws a clear IllegalStateException for a query or index call, rather than NullPointerException (#426).
  • A failed CRAM reference lookup names the sequence and the .fai, .gzi and .dict files a CRAM's reference needs (#998, #1732).
  • Dates with a space or a lower-case t or z are parsed (#1217).

VCF and BCF

  • The BCF writer keeps an interior missing value in a vector, sizes each FORMAT vector from its values, sizes strings by their UTF-8 length, writes String INFO values whatever their comma count (#1063), accepts a Flag line with a non-zero Number, and masks n_sample to 24 bits.
  • A missing value inside a BCF vector no longer shifts the values after it.
  • INFO values are typed by their INFO line and FORMAT values by their FORMAT line, where an INFO field sharing an ID with a FORMAT field took the FORMAT line's type.
  • getAttributeAsInt, getAttributeAsDouble, getAttributeAsBoolean, getAttributeAsIntList and getAttributeAsDoubleList return the default for a missing value read from VCF (#1228, #1073).
  • Spaces in INFO values are accepted (#1667).
  • A malformed genotype is reported as a TribbleException naming the sample and key.
  • VCFFileReader opens VCF 3.2 and 3.3, and reads a 3.x record with FILTER=PASS as passing.
  • smartMergeHeaders promotes Integer and Float to Float in either order, and keeps every contig when the inputs' dictionaries differ (#1574).
  • Genotype.sameGenotype ignoring phase tells polyploid genotypes apart by allele counts.
  • getStructuralVariantType() returns DEL for an SVTYPE of DEL:ME.
  • VariantContext.hasID() is false for a deserialized record without an ID.
  • An empty VCF is reported as empty (#973).
  • toString() no longer decodes lazily decoded genotypes (#1011).
  • Closing a VCF or BCF writer, or a BlockCompressedOutputStream, twice does nothing (#469).
  • VCF and BCF are read and written without commons-jexl on the class path.
  • VCFFileReader opens a path in a zip or jar file system.
  • VariantContextWriterBuilder keeps an IndexCreator the caller supplied for block-compressed VCF.

Indexes and tabix

  • A tabix index with a sequence that has no records is written correctly.
  • TabixReader returns a last line without a newline, strips a CR before the newline, accepts contig names containing : or - (#1017), rejects a plain-gzip file, and names the index files it looked for.
  • A Tribble index with a byte of 0x80 or above in a name is read (#1614).

FASTA and references

  • FastaSequenceIndexCreator indexes a FASTA with blank lines (#1748) or a last line without a newline.
  • A FASTA whose first lines are ; comments can be read and indexed.
  • A sequence longer than 2^30 bases read without a dictionary no longer fails (#1380).
  • A gzipped (not bgzipped) FASTA with a .fai is read sequentially rather than rejected (#1143).
  • Opening an indexed FASTA checks that it matches its .fai.
  • Indexed lookups from several threads return the right bases (#1749), and bgzipped lookups no longer re-inflate a block each time (#1131).
  • A bgzipped FASTA from FastaReferenceWriter can be opened as indexed, and GZIIndex.buildIndex handles more than 2 GiB of data.
  • Closing a FastaReferenceWriter given no sequences writes an empty FASTA (#1498).

Input, output and utilities

  • Gzipped and bgzipped input from pipes, sockets and URLs is no longer silently truncated (#1691).
  • A BGZF file made by joining others is read to its end.
  • IOUtil.isGZIPInputStream checks only the gzip header.
  • FTP works with strict servers, on any port, and fails cleanly for a missing file (#470, #797, #463, #464, #618, #623). A reader picks the format of a file over FTP by its name, so a CRAM or SAM over FTP no longer opens as BAM, and a BAM whose name doesn't end in .bam is no longer opened as one.
  • SeekableMemoryStream.read(buffer, offset, 0) returns 0, and SeekablePathStream.read() no longer returns 0 for an empty channel read (#1399).
  • IOUtil.deletePaths given a single Path deletes only that path.
  • IOUtil.assertFileIsWritable and assertDirectoryIsWritable accept outputs on NFS servers whose access checks disagree with their ACLs (#1671).
  • ProcessExecutor.executeAndReturnInterleavedOutput no longer deadlocks on large output.
  • SortingCollection buffers its temporary files on large heaps (#1741), and SortingLongCollection clamps its buffer as documented.
  • TagFilter accepts a list of any type (#1082).
  • Histogram.getMin, getMax and getMode throw IllegalStateException on an empty histogram (#1657).
  • A malformed BED or GFF3 line is reported with its file, column and text (#709).
  • The published POM lists the Apache 2.0 and LGPL licences as well as MIT (#1710).

Full Changelog: 5.0.2...6.0.0