Peptacular parses ProForma 2.1 peptide sequences and calculates their masses, fragments, and isotopic distributions. It's for anyone working with peptide-level proteomics data in Python who wants exact masses and fragment ions without hand-rolling ProForma parsing and mass tables. It's built on tacular's lookup data, and its fragments export directly as mzPAF strings readable by paftacular.
- Full ProForma 2.1 parsing into a chainable, editable
ProFormaAnnotationobject — or use the functional API directly on strings. - Mass, m/z, composition, and predicted isotopic distributions, with monoisotopic and average mass support.
- Enzymatic digestion with missed cleavages, semi-specific, and non-specific modes.
- Fragment ion generation for 20+ ion types, exportable straight to mzPAF strings for paftacular.
- Batch-friendly: functional API calls on lists of sequences parallelize
automatically, with per-item error collection. Pass FASTA/PEFF entries from
fastatacular straight in: any object with a
sequencestring works. - Type-annotated throughout, plus optional Pyteomics, psm_utils, AlphaBase, and MCP integrations.
pip install peptacularOptional integrations install as extras:
pip install "peptacular[pyteomics]"
pip install "peptacular[psm-utils]"
pip install "peptacular[alphabase]"
pip install "peptacular[mcp]"
pip install "peptacular[numpy]" # fragment_arrays(): ions as numpy columnsSee the interoperability guide for supported conversions.
import peptacular as pt
# Parse a sequence into a ProFormaAnnotation
peptide = pt.parse("PEM[Oxidation]TIDE")
# Calculate mass and m/z
print(peptide.mass()) # 849.3426002717299
print(peptide.mz(charge=2)) # 425.6785766024859
# Chained edits return a modified annotation
print(peptide.set_charge(2).set_peptide_name("Peptacular").serialize())
# (>Peptacular)PEM[Oxidation]TIDE/2Digest a protein and generate fragment ions that round-trip through paftacular's mzPAF parser:
import peptacular as pt
peptides = pt.digest("MKVLATSAGERTIDEK", enzyme="trypsin", missed_cleavages=1)
print([seq for seq, _ in peptides])
# ['MK', 'MKVLATSAGER', 'VLATSAGER', 'VLATSAGERTIDEK', 'TIDEK']
fragments = pt.fragment("PEPTIDE", ion_types=("b", "y"), charges=[1])
print(fragments[1].to_mzpaf()) # b2{PE}The functional API operates on lists directly, auto-parallelizing for larger batches:
import peptacular as pt
peptides = ["[Acetyl]-PEPTIDES", "<13C>ARE", "SICK/2"]
print(pt.mass(peptides)) # [928.4025574375299, 388.23835027296, 451.24535797517194]
print(pt.mz(peptides, charge=2)) # [465.20855518538593, 195.12645160310103, 225.62267898758597]For streaming input and per-item error collection instead of a raised exception, see the streaming guide:
import peptacular as pt
results = pt.batch("mass", ["PEPTIDE", "PEP[UnknownModification]TIDE"], errors="collect")
print(results[0].value) # 799.3599640328299
print(results[1].error.code) # unresolved_modificationRaised errors are typed and all subclass pt.PeptacularError (a ValueError):
invalid ProForma raises pt.ProFormaFormatError, an unresolved modification
pt.UnknownModificationError, and so on. See the
streaming guide for the full list.
Expand an ambiguous modification into its localization isomers and find the fragment ions that tell them apart. Candidate sites come from the ProForma string alone; peptacular has no built-in list of which residues a mod can sit on:
import peptacular as pt
isomers = pt.localization_isomers("PEP(ST)[Phospho]IDE")
print([a.serialize() for a in isomers]) # ['PEPS[Phospho]TIDE', 'PEPST[Phospho]IDE']
ions = pt.site_determining_ions(isomers, ion_types=("b", "y"), charges=(1,))
print([[f"{f.ion_type}{f.position}" for f in frags] for frags in ions]) # [['b4', 'y4'], ['b4', 'y4']]| Area | Entry points |
|---|---|
| Digestion | pt.digest, pt.semi_digest, pt.nonspecific_digest |
| Fragmentation | pt.fragment, pt.fast_fragment |
| Localization | pt.localization_isomers, pt.candidate_sites, pt.site_determining_ions, pt.pairwise_site_determining_ions (guide) |
| Isotopes | pt.isotopic_distribution, pt.brain_isotopic_distribution |
| Tables | pt.digest_records, pt.fragment_records (plain dicts for pandas or polars), pt.fragment_arrays (numpy columns) |
| Batch / streaming | pt.batch, pt.iter_batch, pt.diagnose (read FASTA with fastatacular) |
| JSON interchange | see the JSON serialization guide |
peptacular does not ship pandas or polars. pt.digest_records and pt.fragment_records
return a list of plain dicts (strings, numbers, booleans, None), one per peptide or ion,
which either library turns into a table. Column names are listed in
pt.DIGEST_RECORD_KEYS and pt.FRAGMENT_RECORD_KEYS:
import peptacular as pt
rows = pt.digest_records("MKVLATSAGERTIDEK", "trypsin", missed_cleavages=1)
print(rows[0]) # {'peptide': 'MK', 'stripped_sequence': 'MK', 'start': 0, 'end': 2, 'missed_cleavages': 0, 'semi': False, 'accession': None}
ions = pt.fragment_records(pt.fragment("PEPTIDE/2", ion_types=("b", "y"), charges=(1, 2)))
print(ions[1]["ion_type"], ions[1]["position"], ions[1]["charge_state"], ions[1]["mzpaf"]) # b 2 1 b2{PE}
# pandas.DataFrame(rows) or polars.DataFrame(ions) gives a tableA FASTA entry's accession (or a PEFF entry's db_unique_id) is copied into each digest row.
For many peptides, pt.fragment_arrays (needs pip install "peptacular[numpy]") returns the
same ions as pt.fragment as a dict of numpy columns, one row per ion, with a peptide_index
column. It is about 10x faster than building a table from Fragment objects:
cols = pt.fragment_arrays(["PEPTIDE/2", "PEM[Oxidation]K"], ion_types=("b", "y"), charges=(1, 2))
print(cols["peptide_index"][:3].tolist(), cols["mz"][:3].round(4).tolist()) # [0, 0, 0] [98.06, 227.1026, 324.1554]
# polars.DataFrame(cols) or pyarrow.table(cols) takes the dict as isSee the tables guide.
Peptacular includes 12 optional MCP tools for agents to inspect annotations,
calculate theoretical properties, digest protein sequences, and transform
annotations. Calls accept small inline batches and return results directly,
with no stored data or job setup. Install with pip install "peptacular[mcp]",
then check the installation:
peptacular-mcp --check
See the local MCP guide for client setup, tool examples, and limits.
- Full docs: peptacular.readthedocs.io
- Changelog: CHANGELOG.md
- ProForma 2.1 compliance status: PROFORMA_COMPLIANCE.md
- Contributing: CONTRIBUTING.md
MIT
Working on a JOSS submission, but in the meantime use:
