Releases: smith-chem-wisc/pyMzLib
Release list
pyMzLib 0.1.1 — Thermo .raw reading fixed
Fixes reading Thermo .raw files, which failed on every platform in 0.1.0. Upgrade with:
pip install --upgrade mzlib
Source: v0.1.0..v0.1.1
mzLib: 1.0.589 (8931f219), unchanged from 0.1.0
Fixed: Thermo .raw files read again (#57)
In 0.1.0, every .raw read failed with:
BridgeError: Method invocation failed on Method[ThreadedFileFactory] Type[ThermoFisher.CommonCore.RawFileReader.RawFileReaderAdapter]
Thermo's RawFileReader looks for its own DLLs on disk, and in 0.1.0 they were packed inside the single-file bridge executable. They now ship as two loose DLLs (~1.2 MB) next to it.
No test caught this because mzLib's C# tests don't run from the packed executable. A new test reads a small .raw through the packaged bridge, and it passed on every OS in CI: Windows, Linux, and macOS on both Intel and Apple Silicon.
mzLibR and mzLibRust get the fix through the mzlib-bridge-<rid>.tar.gz assets below. The archives now include the two DLLs, so extract the whole archive, not just the executable.
Changed: file paths can be pathlib.Path objects (#58)
pride.download returns Path objects. Before this release, the readers, sdrf and flashlfq refused them with "A file path is required", so you had to wrap each one in str(). Any str or os.PathLike now works for input files, out=, output_directory=, and FlashLFQ's spectra list:
raw_files = pymzlib.pride.download("PXD000001", "downloads", category="RAW")
scans = pymzlib.readers.read_spectra(raw_files[0], ms_order=2, limit=5, peaks=True)Also
- The README example now runs top to bottom as written: list a PRIDE project, download its
.raw, read it, digest a protein.
pyMzLib 0.1.0 — on PyPI
The first release on PyPI.
pip install mzlib
import pymzlibThe package installs as mzlib and imports as pymzlib, the same split as pip install scikit-learn / import sklearn. There's no .NET to install and no third-party Python dependencies: each wheel carries its own .NET runtime. One wheel per OS covers every Python from 3.9 up, on Windows x64, Linux x64 (glibc 2.28+), and macOS Intel and Apple Silicon (12+).
Source: v0.1.0.dev6..v0.1.0
mzLib: 1.0.589 (8931f219), unchanged from dev6
Why it can be on PyPI now: the wheels are ~60 MB, down from up to 166
PyPI refuses any file over 100 MiB, and three of the four dev6 wheels were over that. Nearly all of the excess was libtorch, a machine-learning library mzLib pulls in for one retention-time predictor (Chronologer) that no pyMzLib function calls. It's no longer shipped (#54).
| wheel | dev6 | 0.1.0 |
|---|---|---|
| Linux x64 | 165.9 MiB | 56 MiB |
| Windows x64 | 129.4 MiB | 59 MiB |
| macOS Apple Silicon | 101.8 MiB | 59 MiB |
| macOS Intel | 61 MiB | 61 MiB (never had libtorch) |
Bridge output is byte-identical without it. The .NET runtime (~30 MiB) is still in every wheel. CI now fails any wheel over 100 MiB, so a new dependency can't quietly undo this.
The same saving reaches mzLibRust and mzLibR through the mzlib-bridge-<rid>.tar.gz assets below.
What's in 0.1.0
Everything from the dev series, now installable in one line:
- Readers: spectra from mzML, Thermo
.raw, Bruker.d, timsTOF.d, MGF and msalign; identify and read all 31 file types mzLib knows, search results included. - PRIDE Archive: search projects by keyword, list a project's files, and download them with filters.
- Peptidoforms: digest an annotated protein, apply its modifications, and fragment every peptide.
- Quantification: FlashLFQ label-free quant with match-between-runs, plus median-polish protein roll-up.
- SDRF experimental design: read an SDRF-Proteomics file, and pool several experiments into one analysis table.
Also fixed
- The FAQ's troubleshooting step said
pip install … pymzlib.pymzlibon PyPI belongs to an unrelated uploader. It now saysmzlib(#55). - The docs' size claims were wrong in a way that mattered: the FAQ said the .NET runtime was "most of why it's 115 MB". It's ~30 MiB, and libtorch was the bulk.
Checksums
SHA256SUMS below covers all four wheels and all four bridge tarballs.
pyMzLib 0.1.0.dev6 — SDRF, PRIDE search, and a new install name
Preview release. Not on PyPI — install from the wheels below.
Source: v0.1.0.dev5..v0.1.0.dev6 (10 PRs)
Contributors: @trishorts
mzLib: 1.0.585 → 1.0.589 (8931f219), across three automatic pin bumps
The install command changed: pip install mzlib
Read this one first, because it is the only thing here that can break a script.
The distribution name is now mzlib, not pymzlib. The import name is unchanged — it is still import pymzlib, and the package directory is still src/pymzlib. Those two names are independent in Python (pip install scikit-learn gives you import sklearn), so no user code changes; only the install line does.
pip install mzlib # was: pip install pymzlib
import pymzlib # unchangedpymzlib was verified unclaimed on PyPI on 2026-07-23 and claimed by an unrelated uploader on 2026-07-29, before this project had published anything. A name nobody has uploaded to is not reserved: PyPI is first-upload-wins, and even a pending trusted publisher does not hold one. mzlib was claimed on 2026-08-16 and is ours.
The rename does not reach mzLibR or mzLibRust. Both take the mzlib-bridge-<rid>.tar.gz asset rather than unzipping a wheel, and the import package they look for inside a wheel is still pymzlib/.
SDRF: the half that says what was searched
pymzlib.sdrf.read() and pymzlib.sdrf.pool(). Every other module here answers what a search found; this is the first that answers what went into it — which sample, which organism part, which replicate — and that is the half you need before results from two experiments can be compared at all.
doc = pymzlib.sdrf.read("PXD059974.sdrf.tsv")
doc.value("characteristics[organism]") # ['Homo sapiens', ...]
pooled = pymzlib.sdrf.pool({"run1.sdrf.tsv": "control", "run2.sdrf.tsv": "treated"})This closes a defect, not only adds surface. mzLib has dispatched SupportedFileType.Sdrf since #1138, so read_records() already accepted a .sdrf.tsv — and returned two columns, header and cells, each an iterable joined with ";" by the generic reflective projection. SDRF's own controlled-vocabulary grammar is semicolon-delimited (NT=Oxidation;AC=UNIMOD:35;TA=M,W,H;MT=Variable is one cell), so the joined string could not be split back apart, nothing disclosed the loss, and the 31-column header was repeated verbatim on every row.
Three things about this reader are unusual, and each is deliberate:
- The payload is row-major, and every other reader here is columnar. SDRF column names are data, not a schema, and they repeat — 649 files in the curated corpus carry
comment[modification parameters]more than once, up to eight times in one file, and one repeats an empty name 23 times. A name-keyed map would keep one occurrence and silently drop the rest. Socolumn_namesis a list that may contain duplicates,rowsis a list of cell lists, and position links them.recordsis still offered, flagged lossy throughhas_repeated_columns. - Rows stay ragged and cells stay raw. PXD059974 has a 46-column header with 17 of 22 rows carrying 42 cells; mzLib preserves that so the file round-trips, and padding would invent cells. Cells are never interpreted, because a cell containing
=and;cannot be told from a CV term by shape —comment[file uri]carries pre-signed URLs withSignature=andExpires=. "not available"is a value, not a null. It is a reserved word an experiment actually wrote, distinct fromNonefor a column the document does not have. Collapsing the two would erase the difference between "we looked and there is none" and "nobody asked".
pool() takes labels, and they matter more than they look: mzLib's default is containing-folder/file-stem, so an unlabelled pool depends on where the files sit and is not reproducible on another machine. The response says so when that fallback was used, and a partially-labelled set is refused outright rather than producing a provenance column that means a chosen name on some rows and a local path on others.
Validation is deliberately absent. mzLib models SDRF's structural rules in SdrfValidator and its vocabulary drift in SdrfDriftLint, but both are internal to the Readers assembly, so the bridge cannot call them. Writing a second opinion here — and again in Rust, and again in R — is exactly the per-binding repair this bridge exists to prevent. Tracked as U8 upstream, where the fix is already written and merely unproposed. A native C# consumer shares the gap: MetaMorpheus writing an SDRF cannot check its own output either, which is what makes it mzLib's problem rather than ours.
PRIDE projects can be found, not just fetched
pymzlib.pride.search(). Every other function in that module — list_files, list_ftp_files, download, download_files — takes an accession you already have. There was no way to find a project from Python: you went to the PRIDE website, found PXD000001 by hand, and came back.
hits = pymzlib.pride.search("plasmodium falciparum schizont")
hits[0].accession, hits[0].highlights # feeds straight into the rest of the moduleA hit is not a project's metadata, and the two types are not interchangeable. PRIDE serves search from a separate Elasticsearch projection in which every controlled-vocabulary field is flattened to a display string — instruments come back as ["Q Exactive"] rather than terms with accessions, contacts as display names, publications as one pre-formatted citation. That is PRIDE's wire, not a simplification chosen here, so PrideProjectSearchResult is its own type. Resolving a display name against a vocabulary to manufacture the missing accession would put an identifier in your hands that PRIDE never asserted, so nothing does.
What search adds over the metadata endpoint is highlights: which fields matched, and with what. Its keys are PRIDE's own field names and cross unchanged.
Two honesty notes, carried through rather than smoothed over:
- Dates are
datetime.date, notdatetime. This endpoint sends a bare calendar date with no time and no offset. Adatetimewould attach a midnight PRIDE never sent, and aDateTimeOffsetwould attach whatever offset the executing machine happens to be in. - Zero means "not reported", and is left as zero. PRIDE omits nothing as null, so absence arrives as
0,""or[]— sampled across 1,600 hits,project_tagsis populated on 2.6%,sdrfon 2.4%.download_count == 0does not mean nobody downloaded it. Same for the empty strings PRIDE ships insidekeywordson ~9% of hits: filtering them here would make Python disagree with mzLib, Rust and R about what a project's keywords are.
No hits is an empty list, not an error. Unlike an accession, a keyword that matches nothing has no typo to protect you from — "nothing matched" is a real finding.
Numbers mzLib fabricated no longer cross as measurements
Two places where mzLib hands back a number that is not a measurement, and the wire had been passing it along.
- A fabricated zero intensity.
ISingleChargeMs1Feature.Intensityis a non-nullable double filled withIntensityApex ?? 0.apex_intensityis an optional column the FLASHDeconv/OpenMS_ms1.featurelayout omits entirely, so every feature of every such file reported 0 — indistinguishable from a real measurement of nothing, inside a view whose whole selling point is that its columns are comparable across files. The column now crosses asnullwhen mzLib had no value. Detected per file, not per file type, because TopFD writes the column and FLASHDeconv does not and both areSupportedFileType.Ms1Feature. - The
-1sentinel.IQuantifiableRecord.RetentionTimeand.MonoisotopicMassare non-nullable doubles assigned literal-1when the source column is absent.read_results()has nulled those since the original readers tranche;read_records()reaches the same properties on the same record types, so the two verbs answered differently for the same column of the same file — and a-1minute could enter your arithmetic looking ordinary.
Both are repairs, not projections: after this the wire disagrees with mzLib about a number. That is allowed here only as a tracked waystation, and both are tracked (U0, U1) — the real fix is nullable members on the two interfaces.
Two wire columns that were quietly wrong
Regression tests, both verified to fail against the previous pin — which is the only thing that makes them regression tests rather than tests.
- MGF negative charge (mzLib #1164). An MGF
CHARGEline carries its sign as a trailing character (CHARGE=2-), which the reader dropped.read_spectra()published charge+2andPositivepolarity for a negative-mode precursor. The sign is not recoverable downstream: a neutral mass computed fromselected_ion_mzandselected_ion_charge_state_guesswas wrong by two proton masses and looked ordinary. - PRIDE manifest truncation (mzLib #1173).
pride filesstopped paging atCount >= total_records. A server understating that header — a stale count, which PRIDE does — had its tail dropped with no error, and becausefile_countandtotal_size_bytesare computed from whatever the pager returned, a truncated manifest reported a smaller project rather than a failure.
MGF now reports MS1 scans, and the caveats say so
mzLib #1165 gave MGF a real MS level: ms_order is taken from the MSLEVEL line when the writer supplied one, and otherwise a block with a precursor reads as MS2 and a block without one as MS1. The caveat that opened "MGF carries no MS1 scans" was true when written and is now false, so it is rewritten rather than loosened — with the reassurance that files predating MSLEVEL all carry PEPMASS and so still read as MS2 throughout.
Because mzLibRust and mzLibR consume these caveats from the bridge binary...
pyMzLib 0.1.0.dev5 — DIA-NN, SDRF, and a .NET 10 bridge
Preview release. Not on PyPI — install from the wheels below.
Source: v0.1.0.dev4..v0.1.0.dev5 (6 PRs)
Contributors: @trishorts
DIA data can now be quantified
The headline. mzLib 1.0.585 added a DIA-NN reader, and it implements IQuantifiableResultFile — so a DIA-NN report is the fourth format that can feed pymzlib.flashlfq.quantify(), alongside MetaMorpheus .psmtsv / .osmtsv and MSFragger psm.tsv.
info = pymzlib.readers.identify("report.tsv")
info.file_type, info.is_quantifiable # ('DiaNnReport', True)Two things about this format are worth knowing before you point anything at it:
- mzLib does not dispatch it on its name. The formats listing reports the extension as
report.tsv, but matching is on the header — a file is a DIA-NN report if its first line carriesFile.Name,Precursor.IdandStripped.Sequencetogether. That is deliberate upstream: whoever ran the search routinely renames the report, andFile.Nameis what separates the long-format report from thepr_matrixreports DIA-NN writes beside it, which carry the other two columns but one column per run. So a renamed report still reads, and areport.tsvthat is not one still will not. - Its retention times are minutes, and
retention_time_unitsays so rather than'unknown'. DIA-NN writes minutes and mzLib converts nothing. Every quantifiable format now reports'minutes'.
SDRF-Proteomics (.sdrf.tsv, the HUPO-PSI experimental-design standard) also reads, through read_records() like any other format. It offers no uniform view — nothing in mzLib consumes it yet; this is the format layer arriving ahead of the code that will use it.
Together these take pyMzLib from 29 recognised formats to 31, and from three quantifiable to four. views == [] is now the answer for fourteen types rather than thirteen.
The bridge is .NET 10
MzLibBridge and its test project move from net8.0 to net10.0, because mzLib did (mzLib #1141) — .NET 8 leaves support in November 2026 and .NET 10 is the current LTS, supported to November 2028. An 8.0.x SDK cannot build a net10.0 project, so this could not be a pin bump on its own.
Nothing changes for you. The bridge ships self-contained: the runtime travels inside the wheel, which is what the works with no .NET installed job proves on a machine with no .NET at all. The same holds for the raw mzlib-bridge-<rid>.tar.gz assets that mzLibRust and mzLibR consume — neither invokes dotnet or names a target framework, so they pick this up silently in the payload.
The Linux floor is unchanged. manylinux_2_28 was the open question, since .NET 10 raises its own Linux baseline; the glibc-floor job installs and runs the linux-x64 wheel inside manylinux_2_28_x86_64 and passes. The wheel tag stays honest and support is not narrowed.
protocol stays 1. This is not a compatibility break for any binding.
Also in this release
- A documented limitation that did not exist is gone (#38) —
digest()'smodifications=Falsewas documented as not a clean control, on the grounds that it discarded UniProt's feature table and with it the signal-peptide and propeptide boundaries mzLib digests at. That was true of a bug which is now fixed: verified on P02768 against the published dev4 bridge,Falseyields the same 195 distinct base sequences and still containsMKWVTFISLLFLFSSAYSandWVTFISLLFLFSSAYS. Nothing is lost, so the caveat said the opposite of the truth and is removed. - A tag that disagrees with the declared version now fails the build (#40) — nothing checked that the tag and
__version__agreed. Cuttingv0.1.0.dev4while__init__.pystill saiddev3would have built four wheels nameddev3, attached them to a page headeddev4, and gone entirely green; only a manual bump kept that release honest. It is worth a hard failure because it is close to unrecoverable — PyPI refuses to reissue a version — and invisible from inside the repo, surfacing only when a user reports installing something other than what the page advertised. - The READMEs listed two of four capabilities (#39) — the GitHub landing page still described pyMzLib as doing PRIDE and peptidoforms; the PyPI-facing
pkg/python/README.mdlisted only PRIDE. Quantification and Readers had both shipped, both had guides, and both were on the docs site.docs/is docs-as-code and--strict-checked in CI, which is why only the READMEs drifted — they now cannot drift again. - The upstream watcher no longer goes red after doing its job (#35) — its first real run opened a correct pin-bump PR and then failed on a cleanup step, which existed to compensate for checks that were assumed missing. They were not missing:
wheelsanddocsboth queue and sit ataction_required, held behind GitHub's approval gate because the author isgithub-actions[bot]. The fallback guarded a case that does not happen and could not have worked if it did.
Built against mzLib 5ba13155 — release 1.0.585.
Full Changelog: v0.1.0.dev4...v0.1.0.dev5
pyMzLib 0.1.0.dev4 — preview (the bridge, publishable at last)
Preview release. Not on PyPI — install from the wheels below.
Why this one matters
This is the first pyMzLib release to publish the bridge itself, not just Python wheels.
v0.1.0.dev3 and everything before it attached wheels only. A wheel is a Python artifact, and two of the three mzLib bindings are not Python: mzLibRust does not know what a wheel is, and mzLibR only read one because its installer was taught to unzip it — an R package reaching through a Python packaging format because nothing neutral was published. Both repositories' live jobs sat at a hard exit 1 waiting for exactly these files.
New assets
| asset | for |
|---|---|
mzlib-bridge-<rid>.tar.gz ×4 |
any binding, in any language — the raw self-contained bridge |
SHA256SUMS |
verifying a download, and re-pinning mechanically instead of transcribing digests by hand |
pymzlib-*.whl ×4 |
pip, as before |
tar.gz rather than zip for the executable bit: a zip can record a Unix mode, but restoring it is the extractor's choice and R's utils::unzip() declines.
The bridge now says which mzLib it is
version gained an mzlib field reporting the mzLib the bridge was built against, as 1.0.0+<commit>:
{"bridge":"1.0.0.0","protocol":1,"runtime":"8.0.27",
"mzlib":"1.0.0+f6b0f0d17f32383918ef895006aaecb71cdb9a7e"}
A native C# consumer never needed this — it references mzLib directly. A binding holds a prebuilt binary and could not answer the question at all, which made a result untraceable to the library that produced it.
protocol stays 1. It, not mzlib, is the compatibility contract; an added field is additive and optional, and every binding projects its absence natively (None / Option::None / NA) so a new binding still works against an older bridge.
Also in this release
- a mid-transfer transport failure is classified
ServiceUnavailablerather than surfacing as an opaqueIOException, so an EBI outage is distinguishable from a bug — and a full disk deliberately is not excused as an outage - a scheduled watcher now opens a pull request when mzLib cuts a release, instead of the pin moving only when someone remembers
Built against mzLib f6b0f0d1.
pyMzLib Preview - MedianPolish
Development preview. Adds median-polish protein quantification — roll a QuantifiedPeptides.tsv up to protein intensities with FlashLFQ's own algorithm, without re-running peak-finding — to the PRIDE, peptidoform, FlashLFQ and readers support from dev1/dev2. Install the wheel for your OS straight from this release — no .NET, no third-party Python deps, Python ≥ 3.9.
Install
Windows
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev3/pymzlib-0.1.0.dev3-py3-none-win_amd64.whlLinux (x86-64, glibc ≥ 2.28)
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev3/pymzlib-0.1.0.dev3-py3-none-manylinux_2_28_x86_64.whlmacOS — Apple Silicon
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev3/pymzlib-0.1.0.dev3-py3-none-macosx_12_0_arm64.whlmacOS — Intel
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev3/pymzlib-0.1.0.dev3-py3-none-macosx_12_0_x86_64.whlNew in this preview — median_polish
Protein quantification is the second half of quantify(). median_polish() runs that half on its own, starting from a peptide table FlashLFQ already wrote:
import pymzlib
# No mzML, no peak-finding — just the roll-up
proteins = pymzlib.flashlfq.median_polish("flashlfq_out/QuantifiedPeptides.tsv")
for g in proteins: # ProteinGroup, ordered by name
print(g.protein_group, g.intensity("run_3"))
# The design is the point: it says which columns are replicates of which sample
proteins = pymzlib.flashlfq.median_polish(
"flashlfq_out/QuantifiedPeptides.tsv",
design=[
{"file_name": "control_1", "condition": "control", "biological_replicate": 0},
{"file_name": "control_2", "condition": "control", "biological_replicate": 1},
{"file_name": "treated_1", "condition": "treated", "biological_replicate": 0},
{"file_name": "treated_2", "condition": "treated", "biological_replicate": 1},
],
use_shared_peptides=True, # let shared peptides contribute
output_directory="reroll", # also write QuantifiedProteins.tsv
)
proteins[0].intensity("control_1") # keyed by "condition_biorep"The engine is mzLib's own CalculateProteinResultsMedianPolish — the identical method the full quantify() runs — so the numbers match what quantify() would have written. Reach for it to re-roll proteins without re-quantifying peptides: a different experimental design, or shared peptides toggled, in seconds rather than another pass over every run.
Three things worth knowing:
- The design groups replicates, and it is checked. Median polish compares each peptide across
samples grouped by condition and biological replicate. A design must name every run in the table
and only runs in the table — a name matching no column, or a column with no design line, is
rejected rather than quietly guessed. With no design, eachIntensity_column becomes its own
biological replicate with a blank condition (what FlashLFQ assumes when it writes the file with no
design) and intensities are keyed by run name instead ofcondition_biorep. Noneand0.0still mean different things. An intensity isNonewhere median polish could
not resolve a number — a degenerate peptide matrix — and0.0where the protein simply was not
measured in that sample, including a group whose only peptides are shared while
use_shared_peptidesis off.- The table reader rejects rather than guesses. A non-numeric intensity cell, an unrecognised
Detection Type_value, and two rows sharing aSequenceare all usage errors naming the line and
column, instead of a corrupt table quietly becoming a plausible-looking table of zeros. A blank
cell is still0.0— that is how FlashLFQ writes "not measured" — and detection type is still
inferred from intensity in the one case it was meant for: noDetection Type_column at all. Run
names containing a dot (QC.2) survive intact rather than being truncated toQCand colliding.
Known divergence
For unfractionated data the QuantifiedProteins.tsv written by output_directory= does not use the same sample labels as the returned objects. FlashLFQ applies the labelling rule with the boolean inverted — labelling by file name exactly when a design is given, and writing Intensity__1 when one is not (mzLib#1128, fixed by mzLib#1129). median_polish() uses the un-inverted rule, so the two disagree until pyMzLib re-pins to a build carrying that fix. Only the labels differ; the values agree either way, and the returned list is the primary result.
Still a preview
Not on PyPI yet. The API may change without deprecation until 0.1.0.
pyMzLib 0.1.0.dev2 — preview (now with readers)
Development preview. Adds readers — identify any result file mzLib recognises and read the quantifiable ones into a uniform record view — to the PRIDE, peptidoform and FlashLFQ support from dev1. Also back-ports the mzLibRust bake-off findings: one bug fix and six documentation corrections. Install the wheel for your OS straight from this release — no .NET, no third-party Python deps, Python ≥ 3.9.
Install
Windows
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev2/pymzlib-0.1.0.dev2-py3-none-win_amd64.whlLinux (x86-64, glibc ≥ 2.28)
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev2/pymzlib-0.1.0.dev2-py3-none-manylinux_2_28_x86_64.whlmacOS — Apple Silicon
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev2/pymzlib-0.1.0.dev2-py3-none-macosx_12_0_arm64.whlmacOS — Intel
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev2/pymzlib-0.1.0.dev2-py3-none-macosx_12_0_x86_64.whlNew in this preview — readers
import pymzlib
# What is this file, and what can I do with it?
info = pymzlib.readers.identify("psm.tsv")
print(info.file_type, info.views) # 'MsFraggerPsm' ['quantifiable']
# Every format mzLib recognises, straight from mzLib rather than a transcribed table
for fmt in pymzlib.readers.formats():
print(fmt.file_type, fmt.extension, fmt.is_quantifiable)
# Read a result file into the uniform record view — columnar, zero dependencies
r = pymzlib.readers.read_results("AllPSMs.psmtsv")
import pandas as pd
pd.DataFrame(r.columns) # one call, no adapter
print(r.caveats) # what this format's numbers do NOT meanThree things worth knowing, because the point of this tranche is that it says them out loud:
- An empty
viewslist is a real answer, not an error. Only 3 of the 29 recognised file
types implement the quantifiable record view; most formats have no cross-format projection at all.
identify()reports that honestly rather than pretending. caveatsis part of the payload. Per-format warnings about what a field actually means — e.g.
MSFragger retention times are in seconds while MetaMorpheus's are in minutes, and nothing in
mzLib converts them.- No default row cap. A result file can carry a million rows; truncating by default would return
a table that looks complete and is not. Uselimit=(which reportstruncated) orout=to write
straight to disk.
Fixed
Peptide.intensity()now returns0.0— neverNone— when the wire value isnull, matching
the documented "0.0 when missing, never None" invariant (#7).Nonestays meaningful for
proteins, which is the signal callers branch on.read_results(out=...)refuses to write to its own input path instead of silently overwriting the
caller's result file.- Six documentation corrections back-ported from the mzLibRust bake-off: the glycation-exclusion
rationale (mzLib#1112), ETD's spurious y-ion series and its effect onfragment_count
(mzLib#1109/#1110),max_threadsas a correctness knob rather than only a performance one
(mzLib#1111), PRIDE's decompressed-size and incomplete-manifest reporting, and the trypsin vs
trypsin|Ppeptide-count figure (37 → 7).
Still a preview
Not on PyPI yet. The API may change without deprecation until 0.1.0.
pyMzLib 0.1.0.dev1 — preview (now with peptidoforms + FlashLFQ)
Development preview. Adds peptidoforms and FlashLFQ label-free quantification to the PRIDE support from dev0. Install the wheel for your OS straight from this release — no .NET, no third-party Python deps, Python ≥ 3.9.
Install
Windows
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev1/pymzlib-0.1.0.dev1-py3-none-win_amd64.whlLinux (x86-64, glibc ≥ 2.28)
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev1/pymzlib-0.1.0.dev1-py3-none-manylinux_2_28_x86_64.whlmacOS — Apple Silicon
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev1/pymzlib-0.1.0.dev1-py3-none-macosx_12_0_arm64.whlmacOS — Intel
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev1/pymzlib-0.1.0.dev1-py3-none-macosx_12_0_x86_64.whlWhat's in it
import pymzlib
# FlashLFQ — label-free quant across mzML runs, with match-between-runs
result = pymzlib.flashlfq.quantify(
psms="AllPSMs.psmtsv",
spectra=["run_3.mzML", "run_4.mzML"],
match_between_runs=True,
)
print(result.peptide_count, result.protein_count, result.mbr_peak_count)
for peak in result.mbr_peaks: # the match-between-runs transfers
print(peak.file_name, peak.sequence, peak.intensity)
# Peptidoforms — digest an annotated UniProt protein and fragment every peptide
digest = pymzlib.peptidoform.fragments("P02768")
print(digest.modification_census.explain())
# PRIDE Archive — list and download a project's files
files = pymzlib.pride.list_files("PXD000001")FlashLFQ guide: https://smith-chem-wisc.github.io/pyMzLib/guides/flashlfq/ · full docs: https://smith-chem-wisc.github.io/pyMzLib/
Notes
- mzML-only for FlashLFQ for now (convert
.raw/.dfirst). - For match-between-runs, read
result.peaks— the peptide roll-up doesn't carry every transfer. - Preview release; the API may change before 1.0. Built from mzLib
525cb7c8;pymzlib.bridge_version()reports the exact provenance.
pyMzLib 0.1.0.dev0 — preview
A development preview of pyMzLib — mzLib for Python. Not on PyPI yet; install the wheel for your OS straight from this release. No .NET to install, no third-party Python dependencies, Python ≥ 3.9.
Install
Windows
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev0/pymzlib-0.1.0.dev0-py3-none-win_amd64.whlLinux (x86-64, glibc ≥ 2.28)
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev0/pymzlib-0.1.0.dev0-py3-none-manylinux_2_28_x86_64.whlmacOS — Apple Silicon
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev0/pymzlib-0.1.0.dev0-py3-none-macosx_12_0_arm64.whlmacOS — Intel
pip install https://github.com/smith-chem-wisc/pyMzLib/releases/download/v0.1.0.dev0/pymzlib-0.1.0.dev0-py3-none-macosx_12_0_x86_64.whlWhat's in it
import pymzlib
# PRIDE Archive — list and download a project's files
files = pymzlib.pride.list_files("PXD000001")
# Peptidoforms — digest an annotated UniProt protein and fragment its peptides
digest = pymzlib.peptidoform.fragments("P02768")
print(digest.modification_census.explain())Guides: PRIDE · Peptidoforms · full docs at https://smith-chem-wisc.github.io/pyMzLib/
Notes
- Preview release: the API may change before 1.0.
- Each wheel bundles a self-contained .NET payload for its platform, so the download is large (48–152 MB) and no .NET runtime is required.
- Built from mzLib commit
525cb7c8;pymzlib.bridge_version()reports the exact provenance.