Skip to content

Lookup

mzmlpy.lookup.SpectrumLookup

SpectrumLookup(
    file_object: FileInterface,
    *,
    count: int | None = None,
    id_regex: str | None = None
)

Bases: BaseLookup[Spectrum]

Lookup interface for spectra.

Source code in src/mzmlpy/lookup.py
def __init__(self, file_object: FileInterface, *, count: int | None = None, id_regex: str | None = None) -> None:
    self._file_object = file_object
    self._count = count
    self._id_regex = id_regex

count property

count: int | None

Get count of items.

ids property

ids: list[str]

Native ids of all items, in file order, without parsing the items.

filter

filter(
    *,
    ms_level: int | None = None,
    rt: float | None = None,
    rt_range: (
        tuple[float | None, float | None] | None
    ) = None,
    rt_tolerance: float = 30.0,
    polarity: Polarity | None = None,
    precursor_mz: float | None = None,
    precursor_mz_range: (
        tuple[float | None, float | None] | None
    ) = None,
    mz_tolerance: float = 20.0,
    mz_tolerance_unit: ToleranceUnit = "ppm",
    spectrum_type: (
        Literal["centroid", "profile"] | None
    ) = None,
    ook0_range: (
        tuple[float | None, float | None] | None
    ) = None,
    drift_time_range: (
        tuple[float | None, float | None] | None
    ) = None,
    faims_voltage_range: (
        tuple[float | None, float | None] | None
    ) = None
) -> Iterator[Spectrum]

Lazily select spectra by metadata, without decoding binary arrays.

Criteria are combined with AND. Tuples are inclusive *_range bounds, either end None for open. Point queries follow tdfpy's query: rt matches within rt_tolerance seconds and precursor_mz within mz_tolerance ppm (or Da with mz_tolerance_unit="da"). Pass a point or its range, not both. See :class:SpectrumFilter for how each criterion matches. Keep the reader open while iterating.

With an indexed reader (access strategy plain, rapidgzip or memory; stream and embedded scan every spectrum), the first retention-time query reads the scan times of every spectrum once, from the metadata before each record's binary arrays, and caches them. It and later queries then read in full only the spectra inside the window. Record order does not matter.

Raises:

Type Description
MzmlError

A criterion is invalid, or both a point and its range were given.

Source code in src/mzmlpy/lookup.py
def filter(
    self,
    *,
    ms_level: int | None = None,
    rt: float | None = None,
    rt_range: tuple[float | None, float | None] | None = None,
    rt_tolerance: float = 30.0,
    polarity: Polarity | None = None,
    precursor_mz: float | None = None,
    precursor_mz_range: tuple[float | None, float | None] | None = None,
    mz_tolerance: float = 20.0,
    mz_tolerance_unit: ToleranceUnit = "ppm",
    spectrum_type: Literal["centroid", "profile"] | None = None,
    ook0_range: tuple[float | None, float | None] | None = None,
    drift_time_range: tuple[float | None, float | None] | None = None,
    faims_voltage_range: tuple[float | None, float | None] | None = None,
) -> Iterator[Spectrum]:
    """Lazily select spectra by metadata, without decoding binary arrays.

    Criteria are combined with AND. Tuples are inclusive ``*_range`` bounds, either end None
    for open. Point queries follow tdfpy's ``query``: ``rt`` matches within ``rt_tolerance``
    seconds and ``precursor_mz`` within ``mz_tolerance`` ppm (or Da with
    ``mz_tolerance_unit="da"``). Pass a point or its range, not both. See
    :class:`SpectrumFilter` for how each criterion matches. Keep the reader open while
    iterating.

    With an indexed reader (access strategy ``plain``, ``rapidgzip`` or
    ``memory``; ``stream`` and ``embedded`` scan every spectrum), the first retention-time
    query reads the scan times of every spectrum once, from the metadata before each
    record's binary arrays, and caches them. It and later queries then read in full only the
    spectra inside the window. Record order does not matter.

    Raises:
        MzmlError: A criterion is invalid, or both a point and its range were given.
    """
    check_point("rt", rt)
    check_point("precursor_mz", precursor_mz)
    tolerance_range(None, rt_tolerance, "rt_tolerance")
    mz_tolerance_range(None, mz_tolerance, mz_tolerance_unit)
    if rt is not None:
        if rt_range is not None:
            raise MzmlError("pass rt or rt_range, not both")
        rt_range = tolerance_range(rt, rt_tolerance, "rt_tolerance")
    if precursor_mz is not None:
        if precursor_mz_range is not None:
            raise MzmlError("pass precursor_mz or precursor_mz_range, not both")
        precursor_mz_range = mz_tolerance_range(precursor_mz, mz_tolerance, mz_tolerance_unit)
    predicate = SpectrumFilter(
        ms_level=ms_level,
        rt_range=rt_range,
        polarity=polarity,
        precursor_mz_range=precursor_mz_range,
        spectrum_type=spectrum_type,
        ook0_range=ook0_range,
        drift_time_range=drift_time_range,
        faims_voltage_range=faims_voltage_range,
    )
    # Only a retention-time query on a reader that can read spectrum heads needs the count;
    # on a stream reader counting would read the whole file before the first result.
    if predicate.rt_range is not None and self._file_object.can_read_spectrum_heads():
        count = self.count
        if count is not None:
            return self._filter_rt_window(predicate, predicate.rt_range, count)
    return (spectrum for spectrum in self if predicate.matches(spectrum))

get_by_index

get_by_index(index: int) -> T

Get item by index. Negative indices count from the end, like a list.

Source code in src/mzmlpy/lookup.py
def get_by_index(self, index: int) -> T:
    """Get item by index. Negative indices count from the end, like a list."""
    if isinstance(index, bool) or not isinstance(index, int):
        raise TypeError(f"index must be an int, got {type(index).__name__}")
    if index < 0:
        # Normalize against the count so lookup[-1] mirrors slice behavior (lookup[-1:]).
        count = self.count
        if count is None:
            raise IndexError(f"index {index} out of range: negative indices need a known count")
        if index + count < 0:
            valid = f"valid indices are -{count} to {count - 1}" if count else "the lookup is empty"
            raise IndexError(f"index {index} out of range: {valid}")
        index += count
    return self._get_by_index_impl(index)

get_by_id

get_by_id(identifier: str) -> T

Get item by native id, or by the id_regex key when the reader was given one.

Raises:

Type Description
MzmlRecordNotFoundError

No record has this id (also a KeyError).

TypeError

identifier is not a string.

Source code in src/mzmlpy/lookup.py
def get_by_id(self, identifier: str) -> T:
    """Get item by native id, or by the ``id_regex`` key when the reader was given one.

    Raises:
        MzmlRecordNotFoundError: No record has this id (also a ``KeyError``).
        TypeError: ``identifier`` is not a string.
    """
    if not isinstance(identifier, str):
        raise TypeError(f"id must be a str, got {type(identifier).__name__}")
    try:
        return self._get_by_exact_id(identifier)
    except KeyError:
        if self._id_regex is not None and (mapped := self._id_map.get(identifier)):
            return self._get_by_exact_id(mapped)
        raise

get_by_slice

get_by_slice(slice_obj: slice) -> list[T]

Get items by slice notation.

Source code in src/mzmlpy/lookup.py
def get_by_slice(self, slice_obj: slice) -> list[T]:
    """Get items by slice notation."""
    if self.count is None:
        # Don't know count - must iterate all and slice
        items: list[T] = list(self)
        return items[slice_obj]
    # Know count - use slice.indices() to handle all cases
    start, stop, step = slice_obj.indices(self.count)
    return [self.get_by_index(i) for i in range(start, stop, step)]

mzmlpy.lookup.ChromatogramLookup

ChromatogramLookup(
    file_object: FileInterface,
    *,
    count: int | None = None,
    id_regex: str | None = None
)

Bases: BaseLookup[Chromatogram]

Lookup interface for chromatograms.

Source code in src/mzmlpy/lookup.py
def __init__(self, file_object: FileInterface, *, count: int | None = None, id_regex: str | None = None) -> None:
    self._file_object = file_object
    self._count = count
    self._id_regex = id_regex

count property

count: int | None

Get count of items.

ids property

ids: list[str]

Native ids of all items, in file order, without parsing the items.

get_by_index

get_by_index(index: int) -> T

Get item by index. Negative indices count from the end, like a list.

Source code in src/mzmlpy/lookup.py
def get_by_index(self, index: int) -> T:
    """Get item by index. Negative indices count from the end, like a list."""
    if isinstance(index, bool) or not isinstance(index, int):
        raise TypeError(f"index must be an int, got {type(index).__name__}")
    if index < 0:
        # Normalize against the count so lookup[-1] mirrors slice behavior (lookup[-1:]).
        count = self.count
        if count is None:
            raise IndexError(f"index {index} out of range: negative indices need a known count")
        if index + count < 0:
            valid = f"valid indices are -{count} to {count - 1}" if count else "the lookup is empty"
            raise IndexError(f"index {index} out of range: {valid}")
        index += count
    return self._get_by_index_impl(index)

get_by_id

get_by_id(identifier: str) -> T

Get item by native id, or by the id_regex key when the reader was given one.

Raises:

Type Description
MzmlRecordNotFoundError

No record has this id (also a KeyError).

TypeError

identifier is not a string.

Source code in src/mzmlpy/lookup.py
def get_by_id(self, identifier: str) -> T:
    """Get item by native id, or by the ``id_regex`` key when the reader was given one.

    Raises:
        MzmlRecordNotFoundError: No record has this id (also a ``KeyError``).
        TypeError: ``identifier`` is not a string.
    """
    if not isinstance(identifier, str):
        raise TypeError(f"id must be a str, got {type(identifier).__name__}")
    try:
        return self._get_by_exact_id(identifier)
    except KeyError:
        if self._id_regex is not None and (mapped := self._id_map.get(identifier)):
            return self._get_by_exact_id(mapped)
        raise

get_by_slice

get_by_slice(slice_obj: slice) -> list[T]

Get items by slice notation.

Source code in src/mzmlpy/lookup.py
def get_by_slice(self, slice_obj: slice) -> list[T]:
    """Get items by slice notation."""
    if self.count is None:
        # Don't know count - must iterate all and slice
        items: list[T] = list(self)
        return items[slice_obj]
    # Know count - use slice.indices() to handle all cases
    start, stop, step = slice_obj.indices(self.count)
    return [self.get_by_index(i) for i in range(start, stop, step)]