Skip to content

pysmo

Documentation: https://docs.pysmo.org

Source Code: https://github.com/pysmo/pysmo


Pysmo leverages modern Python (3.12+) to bring type safety and clean abstractions to seismology code.

Protocol-based design

Pysmo defines its core types — Seismogram, Station, Event — as Protocol classes (structural subtyping). Any object that has the right attributes satisfies the protocol; no inheritance required. This means pysmo functions work with your classes out of the box, as long as they look like the right type.

Runtime validation with attrs and beartype

Pysmo's concrete "Mini" classes (e.g. MiniSeismogram) are built with attrs and validated at runtime by beartype. Fields carry validators and converters — a datetime without tzinfo=UTC or a negative sampling interval is rejected immediately, not silently propagated.

Separation of storage and processing

File formats bundle many fields together. Pysmo splits them into narrowly scoped protocol types so that processing code stays simple, testable, and reusable across projects. A SAC object exposes .seismogram, .station, and .event views — each satisfying the corresponding protocol — without coupling your analysis code to the SAC format.

Quick Start

from pysmo import Seismogram, MiniSeismogram
from pysmo.classes import SAC
from pysmo.functions import detrend, normalize, resample

# Read a SAC file — access seismogram data via protocol-typed views
sac = SAC.from_file("myfile.sac")
seis = sac.seismogram  # satisfies the Seismogram protocol

# Process using built-in functions
detrend(seis)
normalize(seis)
resample(seis, seis.delta * 2)

# Write a function that works with ANY Seismogram implementation
def print_info(seismogram: Seismogram) -> None:
    print(f"Start: {seismogram.begin_time}")
    print(f"Samples: {len(seismogram)}, dt: {seismogram.delta}")

print_info(seis)  # works with SacSeismogram

# ...or create a lightweight seismogram from scratch
mini = MiniSeismogram(data=seis.data, delta=seis.delta, begin_time=seis.begin_time)
print_info(mini)  # works with MiniSeismogram too — same protocol

Key Concepts

Concept Python Feature Pysmo Example
Structural subtyping Protocol + @runtime_checkable Seismogram, Station, Event
Validated data classes attrs with field validators MiniStation(name="STA", latitude=48.2, ...)
Runtime type checking beartype + Annotated types PositiveTimedelta, UnitFloat
Generic functions PEP 695 type parameters def crop[T: Seismogram](...) -> T
Format adapters Descriptors + __set_name__ SAC.seismogram, SAC.station

Why Protocols?

Traditional seismology libraries often require you to inherit from a base class or convert data into a library-specific format. Pysmo takes a different approach: functions accept any object that satisfies a protocol. You can use pysmo functions with your own classes — no subclassing, no format conversion, no vendor lock-in.

# Your own class — no pysmo base class needed
@dataclass
class MySeismogram:
    begin_time: datetime
    delta: timedelta
    data: np.ndarray
    def __len__(self) -> int:
        return len(self.data)

# pysmo functions just work
from pysmo.functions import detrend
detrend(MySeismogram(...))  # satisfies the Seismogram protocol