Metadata-Version: 2.4
Name: run-afp
Version: 0.1.2
Summary: Another Fastx Parser — tiny, dependency-free FASTA/FASTQ reader with transparent gzip/bzip2/zip/zstd decompression.
Author-email: "Darrin T. Schultz" <darrin.schultz@univie.ac.at>
License: MIT
Project-URL: Homepage, https://github.com/conchoecia/afp
Project-URL: Source code, https://github.com/conchoecia/afp
Project-URL: odp, https://github.com/conchoecia/odp
Keywords: fasta,fastq,sequence,parser,bioinformatics
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: zstd
Requires-Dist: zstandard>=0.18; extra == "zstd"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: zstandard>=0.18; extra == "dev"
Requires-Dist: bump-my-version; extra == "dev"
Dynamic: license-file

# afp — Another Fastx Parser

[![CI](https://github.com/conchoecia/afp/actions/workflows/ci.yml/badge.svg)](https://github.com/conchoecia/afp/actions/workflows/ci.yml)

A tiny, dependency-free Python reader/writer for **FASTA** and **FASTQ** files
with transparent `gzip` / `bzip2` / `zip` / `zstandard` decompression. Standard
library only — `zstandard` is an optional extra used only for `.zst` inputs.

The whole module is a single file: [`afp.py`](afp.py).

## Install

Three ways to use it:

**Drop the file into your project:**

```sh
curl -O https://raw.githubusercontent.com/conchoecia/afp/main/afp.py
# put afp.py somewhere on your python path
```

**Or pip-install:**

```sh
pip install run-afp               # core, no extras
pip install "run-afp[zstd]"       # also read .zst-compressed files
pip install "run-afp[dev]"        # pytest + zstandard for development
```

The PyPI distribution is `run-afp` (the bare `afp` name was already taken).
The import name stays `import afp`.

**Or vendor inside another repo:** copy `afp.py` into your `dependencies/`
directory, add that directory to `sys.path`, then `import afp`.

## Quick start

```python
import afp

# Auto-detects FASTA vs FASTQ from the first byte, and gzip/bzip2/zip/zstd
# compression from the file's magic bytes (not its extension).
for rec in afp.parse("reads.fq.gz"):
    print(rec.id, len(rec.seq), rec.qual[:10])

for rec in afp.parse("genome.fa"):
    print(rec.id, rec.desc, rec.seq[:50])
```

Force a specific format if needed:

```python
for rec in afp.parse("weirdly_named_file", format="fasta"):
    ...

# Or use the explicit parsers:
afp.parse_fasta("genome.fa")
afp.parse_fastq("reads.fq")
```

## The `Record` object

```python
class Record:
    id: str             # token after '>' or '@', up to first whitespace
    seq: str            # sequence, newlines stripped
    desc: str | None    # everything after id on the header line (or None)
    qual: str | None    # quality string (FASTQ only; None for FASTA)
```

Records are mutable. You can rewrite `record.id` in place.

```python
rec.format()           # back to FASTA / FASTQ text
rec.format(wrap=80)    # FASTA only: wrap sequence at 80 columns
len(rec)               # length of seq
"ACGT" in rec          # membership on the sequence string
list(rec)              # iterate over letters
```

## Writing

```python
afp.write(records, "out.fa")          # plain
afp.write(records, "out.fa.gz")       # auto-gzip from .gz extension
afp.write(records, "out.fq.gz")       # FASTQ if the first record has `qual`
afp.write(records, "out.fa", wrap=80) # wrapped FASTA
```

Mixing FASTA and FASTQ records in a single output stream is rejected.

## Compression helpers

```python
afp.detect_compression("file")   # 'gzip' | 'bzip2' | 'zip' | 'zstd' | 'none'
afp.get_open_func("file.gz")     # returns gzip.open
```

`detect_compression` reads only the first 4 bytes — it's cheap to call.

## Why

Built for projects that want to vendor a single Python file rather than pull
in a multi-megabyte sequence toolkit, under a permissive license they can
carry through to their own code. The whole module is one ~400-line file, no
external runtime dependencies, no compiled extensions.

## License

MIT — see `LICENSE`.
