Skip to content

Releases: smith-chem-wisc/pyMzLib

pyMzLib 0.1.1 — Thermo .raw reading fixed

Choose a tag to compare

@trishorts trishorts released this 18 Sep 19:01
c371060

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

Choose a tag to compare

@trishorts trishorts released this 18 Sep 17:57
1e69f01

The first release on PyPI.

pip install mzlib
import pymzlib

The 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. pymzlib on PyPI belongs to an unrelated uploader. It now says mzlib (#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

Choose a tag to compare

@github-actions github-actions released this 07 Sep 22:13
5003c3f

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         # unchanged

pymzlib 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. So column_names is a list that may contain duplicates, rows is a list of cell lists, and position links them. records is still offered, flagged lossy through has_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 with Signature= and Expires=.
  • "not available" is a value, not a null. It is a reserved word an experiment actually wrote, distinct from None for 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 module

A 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, not datetime. This endpoint sends a bare calendar date with no time and no offset. A datetime would attach a midnight PRIDE never sent, and a DateTimeOffset would 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_tags is populated on 2.6%, sdrf on 2.4%. download_count == 0 does not mean nobody downloaded it. Same for the empty strings PRIDE ships inside keywords on ~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.Intensity is a non-nullable double filled with IntensityApex ?? 0. apex_intensity is an optional column the FLASHDeconv/OpenMS _ms1.feature layout 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 as null when mzLib had no value. Detected per file, not per file type, because TopFD writes the column and FLASHDeconv does not and both are SupportedFileType.Ms1Feature.
  • The -1 sentinel. IQuantifiableRecord.RetentionTime and .MonoisotopicMass are non-nullable doubles assigned literal -1 when 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 -1 minute 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 CHARGE line carries its sign as a trailing character (CHARGE=2-), which the reader dropped. read_spectra() published charge +2 and Positive polarity for a negative-mode precursor. The sign is not recoverable downstream: a neutral mass computed from selected_ion_mz and selected_ion_charge_state_guess was wrong by two proton masses and looked ordinary.
  • PRIDE manifest truncation (mzLib #1173). pride files stopped paging at Count >= total_records. A server understating that header — a stale count, which PRIDE does — had its tail dropped with no error, and because file_count and total_size_bytes are 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...

Read more

pyMzLib 0.1.0.dev5 — DIA-NN, SDRF, and a .NET 10 bridge

Choose a tag to compare

@github-actions github-actions released this 15 Aug 20:09
b60afe2

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 carries File.Name, Precursor.Id and Stripped.Sequence together. That is deliberate upstream: whoever ran the search routinely renames the report, and File.Name is what separates the long-format report from the pr_matrix reports DIA-NN writes beside it, which carry the other two columns but one column per run. So a renamed report still reads, and a report.tsv that is not one still will not.
  • Its retention times are minutes, and retention_time_unit says 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()'s modifications=False was 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, False yields the same 195 distinct base sequences and still contains MKWVTFISLLFLFSSAYS and WVTFISLLFLFSSAYS. 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. Cutting v0.1.0.dev4 while __init__.py still said dev3 would have built four wheels named dev3, attached them to a page headed dev4, 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.md listed 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: wheels and docs both queue and sit at action_required, held behind GitHub's approval gate because the author is github-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)

Choose a tag to compare

@trishorts trishorts released this 09 Aug 16:40

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 ServiceUnavailable rather than surfacing as an opaque IOException, 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

Pre-release

Choose a tag to compare

@Alexander-Sol Alexander-Sol released this 05 Aug 20:37

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.whl

Linux (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.whl

macOS — 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.whl

macOS — 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.whl

New 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, each Intensity_ 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 of condition_biorep.
  • None and 0.0 still mean different things. An intensity is None where median polish could
    not resolve a number — a degenerate peptide matrix — and 0.0 where the protein simply was not
    measured in that sample, including a group whose only peptides are shared while
    use_shared_peptides is off.
  • The table reader rejects rather than guesses. A non-numeric intensity cell, an unrecognised
    Detection Type_ value, and two rows sharing a Sequence are 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 still 0.0 — that is how FlashLFQ writes "not measured" — and detection type is still
    inferred from intensity in the one case it was meant for: no Detection Type_ column at all. Run
    names containing a dot (QC.2) survive intact rather than being truncated to QC and 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)

Choose a tag to compare

@trishorts trishorts released this 24 Jul 16:14
e8aa118

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.whl

Linux (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.whl

macOS — 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.whl

macOS — 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.whl

New 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 mean

Three things worth knowing, because the point of this tranche is that it says them out loud:

  • An empty views list 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.
  • caveats is 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. Use limit= (which reports truncated) or out= to write
    straight to disk.

Fixed

  • Peptide.intensity() now returns 0.0 — never None — when the wire value is null, matching
    the documented "0.0 when missing, never None" invariant (#7). None stays 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 on fragment_count
    (mzLib#1109/#1110), max_threads as a correctness knob rather than only a performance one
    (mzLib#1111), PRIDE's decompressed-size and incomplete-manifest reporting, and the trypsin vs
    trypsin|P peptide-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)

Choose a tag to compare

@trishorts trishorts released this 23 Jul 21:16
4a2ac5c

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.whl

Linux (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.whl

macOS — 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.whl

macOS — 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.whl

What'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/.d first).
  • 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

Pre-release

Choose a tag to compare

@trishorts trishorts released this 23 Jul 19:23
3c1f60e

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.whl

Linux (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.whl

macOS — 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.whl

macOS — 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.whl

What'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.