# pysam puts HTSlib's file handling inside a Python process

> pysam is a Cython wrapper around the HTSlib C API, which is the same library behind samtools, bcftools and tabix. It gives Python code direct access to SAM, BAM, CRAM, VCF, BCF, BED, GFF, GTF, FASTA and FASTQ files, and it inherits that library's version numbers along with its limits.

**pysam-developers/pysam** — Pysam is a Python package for reading, manipulating, and writing genomics data such as SAM/BAM/CRAM and VCF/BCF files. It's a lightweight wrapper of the HTSlib API, the same one that powers samtools, bcftools, and tabix.

- Repository: https://github.com/pysam-developers/pysam
- Website: https://pysam.readthedocs.io/en/latest/
- Stars: 911 · Forks: 304
- Language: Cython
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/pysam-developers-pysam

## A binding, not a reimplementation of SAM parsing

pysam exists because the formats that dominate modern sequencing are awkward to handle with pure Python code. SAM and BAM store large numbers of alignments, the kind produced in bulk by next generation sequencing, and the format exists to store those alignments efficiently. The library handles the reading, the writing and the indexing, so a Python program can treat a BAM file as an iterable of alignment records rather than a binary file it has to parse itself.

The project's own description of its implementation is blunt about what it is: a lightweight wrapper of the samtools C API, with an interface for tabix. The setup.py docstring is more explicit, describing a low-level wrapper around HTSlib's C API written in Cython, and a high-level API for convenient access to data within standard genomic file formats.

That two layer shape is the design decision worth understanding before you write any code. The low level is a thin mapping of the C library, so it tracks htslib closely and exposes whatever that library exposes. The high level is the comfortable one, and it is the layer that will occasionally surprise you when the underlying library has changed. For an audience, that means researchers and pipeline engineers who already live in Python and would otherwise be writing temporary files and calling samtools as a subprocess.

## The htslib, samtools and bcftools trees live inside the repository

The repository root gives away how the package is assembled. Alongside the pysam/ directory that holds the Python and Cython code, there are htslib/, samtools/ and bcftools/ directories. The third-party code is vendored rather than fetched, and the README states the version: the current version of pysam wraps code from htslib-1.24, samtools-1.24 and bcftools-1.24.

Other entries in the root explain the supporting machinery. There is a buildSrc style devtools/ directory, an import/ directory, linker_tests/, tests/, doc/, and platform specific directories for win32/ and what the setup.py refers to as OS X handling. A COPYING file and an AUTHORS file sit next to README.rst, NEWS, INSTALL and MANIFEST.in.

The consequence of vendoring is that the htslib version in a given pysam release is fixed and cannot be updated independently. You cannot ask your package manager for a newer htslib and expect pysam to pick it up. For most users that is a benefit, since the whole point of a pinned release is that the behaviour is known. For operators who have to track a security fix in htslib, it means waiting for a pysam release that carries it, or building from source against a patched tree.

## The README pushes bioconda, and the reason is the build chain

The installation advice in the README is unambiguous about which route to take first. If you use conda, whether miniconda or anaconda, the documented steps are:

```bash
conda config --add channels bioconda
conda config --add channels conda-forge
conda config --set channel_priority strict
conda install pysam
```

The README calls installation through bioconda the recommended way, and gives the reason plainly: it resolves non-Python dependencies and uses pre-configured compilation options, and for OS X this can save a lot of trouble. The strict channel priority line matters more than it looks, because it determines which version of a dependency wins when the bioconda and conda-forge channels disagree, and htslib is exactly the kind of package where the two channels might.

If you are not on conda, the fallback is PyPI, and the README gives a single command:

```bash
pip install pysam
```

The difference between the two routes is not cosmetic. One hands you a prebuilt environment where the htslib native library and its dependencies are already resolved. The other asks your machine to build a C extension against htslib, which needs a working toolchain and a Cython installation.

## Building from source means a Cython and htslib toolchain

The build configuration shows what a source install actually requires. The pyproject.toml declares the build backend and its requirements:

```toml
[build-system]
requires = ["setuptools>=59.0", "Cython>=3,<4"]
build-backend = "setuptools.build_meta:__legacy__"
```

So a source build needs Cython in the 3 series, and the project targets Python 3.9 and above, declared in the same file as requires-python = ">=3.9".

There is a detail in setup.py that explains a common surprise. The build calls the configure script of the vendored htslib with a specific option, and the code comment states the reason: the ref cache is always disabled because its code is omitted from the pysam htslib directory. The call is:

```python
    retcode = subprocess.call(
        "./configure", "--disable-ref-cache", option),
```

In other words, the htslib build is patched at configure time, and that patch is applied unconditionally rather than being left to the user. If you ever need the reference cache behaviour, it is not something you can switch on in a normal pysam build.

The same pyproject.toml shows that the project builds and tests with cibuildwheel, and that the test command is pytest run against the tests/ directory, with a separate linker_tests/ directory for the extension linking itself. That test layout is what you would look at first if a build breaks on a new platform.

## Compression and random access come from the index, not from Python

The docstring in setup.py lists what the module can read and write: SAM, BAM, CRAM, VCF, BCF, BED, GFF, GTF, FASTA and FASTQ, and it also states that the module provides access to the command-line functionality of samtools and bcftools. Two mechanisms there are worth pulling apart, because they are the reason the wrapper is worth having.

The first is compression. BAM and CRAM are compressed containers, and the compression is handled by the native library, not by a Python codec. The second is random access through indexing. A BAM file carries a companion index, and a tabix index allows a VCF or BED file to be queried by region. The tabix interface mentioned in the README is what makes region queries possible, and the pysam/ directory is where that access lives.

For a pipeline that has to pull a few regions out of a large file rather than stream all of it, indexed random access is the feature that removes the need to filter in Python. The catch is that it requires the index to be present and consistent with the file. A stale or missing index is a common failure, and the documentation in the repository does not spell out the recovery procedure.

## Version numbers travel with the htslib release they wrap

The release history explains a lot about the upgrade cost. Recent tags are v0.24.1 on 2026-09-07, v0.24.0 on 2026-04-27 and v0.23.3 on 2025-06-10. The pysam version number and the htslib version are close enough to be confusing at a glance, and the README ties them together explicitly by naming the htslib-1.24, samtools-1.24 and bcftools-1.24 code that the current version wraps.

The maintenance picture is healthy on the surface. The repository is not archived and the last push was on 2026-10-15, with a release on 2026-09-07 before it. But the releases land roughly twice a year in the recent history, and each one carries a new htslib with it, so an upgrade is never a pure Python change.

The licence is MIT, as stated in the pyproject.toml and recorded in the COPYING file. The pyproject.toml names a single author, Andreas Heger, and points readers to release notes at the pysam readthedocs site. Since a pysam release changes the native library under the Python API, the sensible operational habit is to pin the version in an environment file and upgrade deliberately, because a floating dependency can move the whole htslib stack underneath a pipeline that was working.

## Where pysam is the wrong tool

There are cases where adding pysam is a mistake. The first is a one-off inspection. If the task is to look at a BAM file, count something and move on, then a command line tool does the job with less to install, less to pin and less to break. pysam earns its dependency weight when the file handling is inside a larger program that runs repeatedly.

The second case is a native dependency you cannot satisfy. Because the package is a compiled extension over vendored htslib, an environment without a compiler, without a matching Python version or without a working htslib build will not get a working install from PyPI. The conda route exists precisely for this, and an organisation that has banned conda from its build images will be left with source builds and a toolchain to maintain.

The third case is version conflict. A pipeline that already pins htslib through another package, or a cluster where the system htslib is fixed by the administrator, will find that pysam carries its own copy. Because the htslib code is vendored inside the repository, there is no supported way to point pysam at the system library. The duplication is deliberate, and it is the price of reproducible behaviour, but it is a real cost when the same machine already carries a second htslib.

## Conclusion

pysam is the right choice for a bioinformatics pipeline that has to read or write aligned sequencing data from Python without shelling out to samtools for every operation, and the wrong choice for a quick look at a file, where a command line tool is less work. Before adopting it, check which pysam version pairs with the htslib, samtools and bcftools release you already rely on, since the current version wraps the 1.24 line of those projects, and confirm that your environment can install the Cython and htslib build chain, or install through bioconda as the README recommends. If you plan to depend on pysam in a long lived pipeline, pin the version, because a htslib upgrade changes the behaviour underneath it.

## FAQ

### How do I install pysam?

The README recommends the bioconda channel, which resolves non-Python dependencies and uses pre-configured compilation options. The documented steps are to add the bioconda and conda-forge channels, set strict channel priority, and then run conda install pysam. A PyPI install with pip install pysam is also supported.

### Which htslib version does the current pysam release wrap?

The README states that the current version of pysam wraps third-party code from htslib-1.24, samtools-1.24 and bcftools-1.24. The recent pysam tags are v0.24.1, v0.24.0 and v0.23.3.

### Does pysam support CRAM and VCF files, not just BAM?

Yes. The setup.py docstring says pysam provides facilities to read and write SAM, BAM, CRAM, VCF, BCF, BED, GFF, GTF, FASTA and FASTQ files, as well as access to the command-line functionality of samtools and bcftools, with compression and random access through indexing.

### What do I need to build pysam from source?

The build-system requirements in pyproject.toml are setuptools 59.0 or newer and Cython 3, and the project requires Python 3.9 or above. The htslib configure step always runs with the ref cache disabled.

### What licence is pysam released under?

pysam is released under the MIT licence. The pyproject.toml declares it as license = { text = "MIT License" } and the COPYING file at the repository root holds the licence text.

## Sources

- [License: MIT](https://github.com/pysam-developers/pysam/blob/master/LICENSE)
- [Project website](https://pysam.readthedocs.io/en/latest/)
- [pysam-developers/pysam on GitHub](https://github.com/pysam-developers/pysam)
- [README](https://github.com/pysam-developers/pysam/blob/master/README.md)
- [Releases](https://github.com/pysam-developers/pysam/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pysam-developers-pysam
