Metadata-Version: 2.4
Name: fqxv
Version: 0.7.0
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Summary: Read-only Python bindings for the fqxv FASTQ archiver
Keywords: fastq,compression,bioinformatics,genomics
Home-Page: https://github.com/rnabioco/fqxv
License: MIT OR Apache-2.0
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Repository, https://github.com/rnabioco/fqxv

# fqxv (Python)

Read-only Python bindings for [`fqxv`](https://github.com/rnabioco/fqxv), a
Rust toolkit for lossless FASTQ archiving.

```bash
uv pip install fqxv
```

The wheels are `abi3` (one per platform, CPython >= 3.9) and carry the native
codecs, so there is no Rust toolchain to install.

```python
import fqxv

# Stream records (works on every layout, including reordered archives)
for rec in fqxv.open("reads.fqxv"):
    print(rec.name, rec.sequence, rec.quality)  # all bytes

# In-memory input works too
data = open("reads.fqxv", "rb").read()
n = sum(1 for _ in fqxv.open(data))

# Decode only some streams — deselected fields come back as b"" and their coded
# streams are skipped, never entropy-decoded (sequence-only measured ~12x faster
# on ONT long-read archives, ~1.3-1.6x single-threaded on short-read Illumina)
for rec in fqxv.open("reads.fqxv", streams=("seq",)):
    ...                                         # rec.name == rec.quality == b""

# FASTA out, quality skipped entirely — the CLI's `decompress --fasta` as an API
fqxv.decompress_to_path("reads.fqxv", "reads.fasta", fasta=True)

# Whole-archive convenience
fqxv.decompress_to_path("reads.fqxv", "reads.fastq")
raw = fqxv.decompress_to_bytes("reads.fqxv")
info = fqxv.inspect("reads.fqxv")
print(info.reads, info.format_version, info.platform)

# Column projection / random access (plain layout only)
idx = fqxv.open_index("reads.fqxv")
seqs = fqxv.read_sequences("reads.fqxv")        # list[bytes], skips quality
ids = fqxv.read_names("reads.fqxv", groups=[0]) # just the first row group
block0 = fqxv.read_block("reads.fqxv", 0)       # list[Record]

# Read over the network (fqxv.remote, standard-library HTTP). Streaming decodes the
# whole archive on the fly; projection fetches only the column you ask for via HTTP
# byte-range requests.
import fqxv.remote as remote
for rec in remote.stream("https://host/reads.fqxv"):   # or a presigned S3 URL
    ...                                                # streams; no full download
arc = remote.open_index("https://host/reads.fqxv")     # 1 tail GET → footer index
names = arc.names()                                    # ~1% of the file, CRC-checked
print(arc.bytes_fetched, "of", arc.size)
n = remote.download("https://host/reads.fqxv", "reads.fastq")  # → FASTQ on disk

# Any file-like works, so an AWS SDK response streams straight in — no fqxv HTTP:
import boto3
body = boto3.client("s3").get_object(Bucket=b, Key=k)["Body"]
for rec in fqxv.open(body):
    ...
# For concurrent async range fetches, drive fqxv.parse_index_suffix /
# Index.stream_range / fqxv.decode_*_bytes with your own httpx/aiohttp session
# (see fqxv.remote's module docstring).

# Integrity check — raises fqxv.FqxvError on a corrupt archive
fqxv.verify("reads.fqxv")

# Project the archive size/ratio from a FASTQ *without* compressing (gzip/BGZF ok)
est = fqxv.estimate("reads.fastq.gz", level=5)  # also: quality_binning=, sample_reads=
print(est.ratio, est.archive_bytes, est.exhausted)

# Paired mates (or 10x R1/R2/I1/I2) compress into one archive — pass a list and
# their sample sizes are summed. A str/bytes source stays a single input.
est = fqxv.estimate(["R1.fastq.gz", "R2.fastq.gz"])
```

The on-disk `.fqxv` format is stable at 1.0 (a version independent of this
package's), so archives written today stay readable by later releases — and an
archive this build cannot read is refused with an error, never misread.

Projection and `open_index` are unavailable for globally-reordered archives
(`--order any`, `--max`, `--order shuffle`), whose streams are mutually
dependent; use `fqxv.open()` to iterate those — `streams=` selection works on
every layout. Two selection caveats: long-read archives code quality against the
bases, so selecting quality still decodes the sequence internally; and a skipped
stream's integrity digest cannot be checked (run `fqxv.verify()` for a full
check). Everything here is read-only:
`verify` and `estimate` only *measure* — neither writes an archive — and full
compression stays in the CLI.

Full API reference: <https://rnabioco.github.io/fqxv/python/>.

## Build from source

```bash
uv pip install maturin
maturin develop            # from crates/fqxv-python/
```

