MS3Record

class pymseed.MS3Record(reclen=None, encoding=None)[source]

Bases: object

A wrapper for miniSEED data records supporting formats v2 and v3.

MS3Record provides a Python interface to individual miniSEED data records, which are the fundamental unit of the miniSEED time series data format. Each record contains metadata (timing, sample rate, encoding) and optionally, but commonly, data samples.

miniSEED is a format optimized for continuous time series data. It’s widely used in seismology, and related geophysical data for storing and exchanging time series data.

Key Features:
  • Read and write miniSEED v2 and v3 formats

  • Access to all record metadata (timing, sample rates, encoding, etc.)

  • Efficient data sample access via memoryview (zero-copy) or numpy arrays

  • Support for all defined data encodings

Common Usage Patterns:

Reading records (from a file):
>>> from pymseed import MS3Record
>>> for msr in MS3Record.from_file('examples/example_data.mseed', unpack_data=True):
...     print(f"{msr.sourceid}: {msr.numsamples} samples")
...     break # only print the first record to limit testing output
FDSN:IU_COLA_00_L_H_1: 135 samples
Creating records:
>>> from pymseed import MS3Record, DataEncoding
>>> msr = MS3Record()
>>> msr.sourceid = "FDSN:NET_STA_LOC_B_S_X"
>>> msr.set_starttime_str("2024-01-01T00:00:00Z")
>>> msr.samprate = 100.0
>>> msr.encoding = DataEncoding.STEIM2
>>> msr.reclen = 512
>>> for record in msr.generate(data_samples=[1,2,3,4], sample_type='i'):
...     print(f"Packed {len(record)} byte record")
Packed 126 byte record
Working with data samples:

# Get data as memoryview (no copy) data_mv = msr.datasamples # Get data as numpy array (requires numpy, no copy) data_np = msr.np_datasamples # Get data as Python list (copy) data_list = msr.datasamples[:]

All miniSEED record fields are accessible as properties with both
getters and setters where appropriate. Key properties include
- sourceid

FDSN Source Identifier (e.g., “FDSN:IU_COLA_00_B_H_Z”)

- starttime

Start time in nanoseconds since Unix epoch

- samprate

Sample rate in Hz (positive) or interval in seconds (negative)

- numsamples

Number of decoded data samples

- datasamples

Access to the actual data samples

- encoding

Data encoding format (Steim1/2, Float, etc.)

See also

MSTraceList: For working with collections of records as traces

Initialize a new, empty MS3Record.

The structure is initialized with library defaults, which the optional parameters override.

Parameters:
  • reclen (int | None) – Maximum record length in bytes. Common values are 512 and 4096. If None, uses library default.

  • encoding (int | None) – Data encoding format code. Common values: DataEncoding.TEXT, DataEncoding.STEIM1, DataEncoding.STEIM2, DataEncoding.FLOAT32, DataEncoding.FLOAT64. If None, uses library default.

Raises:

Note

To read an existing record instead of creating one, use from_file(), from_buffer(), from_filelike(), or parse().

Example

>>> # Create empty record
>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.sourceid = "FDSN:XX_TEST__B_S_X"
>>> msr.samprate = 20.0
>>>
>>> # Create with specific encoding for Steim2 compression
>>> msr = MS3Record(encoding=11, reclen=4096)
__init__(reclen=None, encoding=None)[source]

Initialize a new, empty MS3Record.

The structure is initialized with library defaults, which the optional parameters override.

Parameters:
  • reclen (int | None) – Maximum record length in bytes. Common values are 512 and 4096. If None, uses library default.

  • encoding (int | None) – Data encoding format code. Common values: DataEncoding.TEXT, DataEncoding.STEIM1, DataEncoding.STEIM2, DataEncoding.FLOAT32, DataEncoding.FLOAT64. If None, uses library default.

Raises:
Return type:

None

Note

To read an existing record instead of creating one, use from_file(), from_buffer(), from_filelike(), or parse().

Example

>>> # Create empty record
>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.sourceid = "FDSN:XX_TEST__B_S_X"
>>> msr.samprate = 20.0
>>>
>>> # Create with specific encoding for Steim2 compression
>>> msr = MS3Record(encoding=11, reclen=4096)
property record: bytes

Return raw, parsed miniSEED record as bytes (copy)

property record_mv: memoryview

Return raw, parsed miniSEED record as a memoryview (no copy).

The record is returned as it was parsed, whatever reclen has been set to since.

The memoryview holds a reference to this MS3Record, keeping its C memory alive for as long as the view is used. It is still tied to this record’s current state: re-parsing, repacking, or freeing the record invalidates the underlying bytes even though the view itself stays reachable. Copy with bytes(...) or .tobytes() to detach from the underlying record.

property reclen: int

Return the parsed record length in bytes, or the maximum length set for packing (-1 for the library default)

property swapflag: int

Return swap flags as raw integer

swapflag_dict()[source]

Return swap flags as dictionary

Return type:

dict[str, bool]

property sourceid: str

Source identifier string identifying the data source.

Returns:

Source identifier string

property formatversion: int

Return format version

property flags: int

Return record flags as raw 8-bit integer

flags_dict()[source]

Record flags as a dictionary.

Decodes the 8-bit flags field into named boolean indicators for data quality assessment.

Returns:

Dictionary with flag names as keys:

’calibration_signals_present’: Calibration signals detected ‘time_tag_is_questionable’: Timing accuracy uncertain ‘clock_locked’: Clock was locked to reference

Return type:

dict[str, bool]

Example

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> flags = msr.flags_dict()
>>> if flags.get('time_tag_is_questionable'):
...     print("Warning: questionable timing")

See also

flags: Raw 8-bit flags value

property starttime: int

Time of the first sample as nanoseconds since Unix epoch.

Depending on the version of miniSEED, and the characteristics of the data source, the start time may not have nanosecond precision. A precision of microseconds is common, along with .0001 second resolution.

Returns:

Nanoseconds since Unix epoch (1970-01-01T00:00:00Z)

Return type:

int

Example

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.starttime = 1609459200000000000  # 2021-01-01T00:00:00Z

See also

starttime_seconds: For working with floating-point seconds starttime_str(): For human-readable time strings

property starttime_seconds: float

Return start time as seconds since Unix/POSIX epoch

starttime_str(timeformat=TimeFormat.ISOMONTHDAY_Z, subsecond=SubSecond.NANO_MICRO_NONE)[source]

Return start time as formatted string

Returns the sentinel strings "ERROR" or "UNSET" when the underlying nanosecond timestamp is the corresponding libmseed sentinel.

Parameters:
Return type:

str

set_starttime_str(value)[source]

Set start time from formatted date-time string

Parameters:

value (str) – Formatted date-time string A number of formats are supported, but the recommended form is YYYY-MM-DDTHH:MM:SS.ssssssZ (RFC 3339/ISO 8601).

Raises:

ValueError – If the string is not a valid date-time string

Return type:

None

Example

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.set_starttime_str("2021-01-01T00:00:00.123456789Z")
>>> msr.starttime_str()
'2021-01-01T00:00:00.123456789Z'

See also

starttime_str(): For formatting the start time as a string

property samprate: float

Nominal sample rate in samples per second (Hz)

Examples

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.samprate = 100.0   # 100 Hz sampling
>>> msr.samprate
100.0
>>> msr.samprate = -10.0   # 10 second intervals
>>> msr.samprate
0.1

See also

samprate_raw: Nominal sample rate in Hz or sample interval in seconds

property samprate_raw: float

Nominal sample rate in samples per second (Hz) or sample interval in seconds.

When positive, this represents samples per second (Hz). When negative, this represents the sample period in seconds (-1/period).

Returns:

Sample rate in Hz (positive) or interval in seconds (negative)

Examples

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.samprate = 100.0   # 100 Hz sampling
>>> msr.samprate_raw
100.0
>>> msr.samprate = -10.0   # 10 second intervals
>>> msr.samprate_raw
-10.0

See also

samprate: Nominal sample rate in Hz

property samprate_period_ns: int

Nominal sample period in nanoseconds.

Examples

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.samprate = 40.0    # 40 Hz sampling
>>> msr.samprate_period_ns
25000000
>>> msr.samprate = -10.0   # 10 second intervals
>>> msr.samprate_period_ns
10000000000

See also

samprate_period_seconds: Nominal sample period in seconds

property samprate_period_seconds: float

Nominal sample period in seconds.

Returned as a 64-bit IEEE-754 float, i.e. the closest binary representation of period_ns / 1_000_000_000. For typical seismic sample periods the value round-trips back to the exact integer nanosecond count, but the float is not bit-identical to the corresponding decimal (e.g. a 40 Hz period is the nearest float to 0.025, not the decimal 0.025 itself), so downstream arithmetic can accumulate small errors. Use samprate_period_ns when you need exact integer-nanosecond arithmetic.

Examples

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.samprate = 40.0    # 40 Hz sampling
>>> msr.samprate_period_seconds
0.025
>>> msr.samprate = -10.0   # 10 second intervals
>>> msr.samprate_period_seconds
10.0

See also

samprate_period_ns: Nominal sample period in nanoseconds (exact integer)

property encoding: int

Data encoding format code specifying how data samples are compressed/stored.

Returns -1 when not set, matching the C library convention used by other unset fields (reclen, samplecnt).

miniSEED supports various encoding formats optimized for different data types and compression requirements. Common encoding values:

  • DataEncoding.TEXT: UTF-8 text

  • DataEncoding.STEIM1: Steim1 32-bit integer compression

  • DataEncoding.STEIM2: Steim2 32-bit integer compression

  • DataEncoding.FLOAT32: IEEE Float32 (little-endian)

  • DataEncoding.FLOAT64: IEEE Float64 (little-endian)

Returns:

Encoding format code, or -1 if not set.

Return type:

int

Examples

>>> from pymseed import MS3Record, DataEncoding
>>> msr = MS3Record()
>>> msr.encoding
-1
>>> msr.encoding = DataEncoding.STEIM2
>>> msr.encoding = DataEncoding.FLOAT32

See also

encoding_str(): Human-readable encoding description

property pubversion: int

Return publication version

property samplecnt: int

Return number of samples specified in fixed header

property crc: int

Return CRC of entire record

property extralength: int

Return length of extra headers in bytes

property datalength: int

Return length of data payload in bytes

property extra: str

Return extra headers as JSON string, or an empty string if none.

get_extra_header(ptr)[source]

Get an extra header value specified by JSON Pointer

Parameters:

ptr (str) – JSON Pointer (RFC 6901) to the header value to get

Returns:

Value of the header, can be a boolean, integer, float, string, or None if the header does not exist.

Raises:
Return type:

bool | int | float | str | None

Examples

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.extra = '''{
...                "FDSN": {
...                  "Time": {
...                    "Quality": 100,
...                    "Correction": 1.234
...                  },
...                  "Flags": {
...                    "MassPositionOffscale": true
...                  }
...                },
...                "Operator": {
...                  "Battery": {
...                    "Status": "CHARGING"
...                  }
...                }}'''
>>> msr.get_extra_header("/FDSN/Time/Quality")
100
>>> msr.get_extra_header("/FDSN/Time/Correction")
1.234
>>> msr.get_extra_header("/FDSN/Flags/MassPositionOffscale")
True
>>> msr.get_extra_header("/Operator/Battery/Status")
'CHARGING'

# Returns None when header does not exist >>> assert msr.get_extra_header(“/Nonexistent/Header”) is None

See also

set_extra_header(): Set an extra header value

set_extra_header(ptr, value)[source]

Set an extra header value specified by JSON Pointer

The header value at the specified JSON Pointer will be set to the value provided, either replacing or creating the value.

Parameters:
  • ptr (str) – JSON Pointer (RFC 6901) to the header value to set

  • value (str | int | float | bool) – Value to set, can be a boolean, number, or string.

Raises:
  • TypeError – If ptr is not a str, or value is not one of the supported types.

  • ValueError – If the header value cannot be set.

Return type:

None

Examples

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.set_extra_header("/FDSN/Time/Quality", 100)
>>> msr.set_extra_header("/FDSN/Time/Correction", 1.234)
>>> msr.set_extra_header("/FDSN/Flags/MassPositionOffscale", True)
>>> msr.set_extra_header("/Operator/Battery/Status", "CHARGING")

See also

merge_extra_headers(): Apply a JSON Merge Patch to extra headers

merge_extra_headers(value)[source]

Apply a JSON Merge (RFC 7386) Patch to extra headers

A JSON Merge Patch can be used to create, update, or delete extra headers.

Parameters:

value (str) – JSON Merge Patch to apply, serialized as a string

Raises:

ValueError – If value is not valid JSON, or the patch cannot be applied

Return type:

None

Examples

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> merge_patch = '{"FDSN": {"Time": {"Quality": 100}}}'
>>> msr.merge_extra_headers(merge_patch)
>>> msr.extra
'{"FDSN":{"Time":{"Quality":100}}}'

Remove time /FDSN/Time/Quality header and add an /FDSN/Time/Correction header: >>> merge_patch = ‘’’{ … “FDSN”: { … “Time”: { … “Quality”: null, … “Correction”: 1.234 … } … }}’’’ >>> msr.merge_extra_headers(merge_patch) >>> msr.extra ‘{“FDSN”:{“Time”:{“Correction”:1.234}}}’

validate_extra_headers(schema_id='FDSN-v1.0', schema_file=None)[source]

Validate the extra headers against a JSON Schema

The selected schema should conform to the JSON Schema 2020-12 specification: https://json-schema.org/draft/2020-12#draft-2020-12

Any specified schema_file will take precedence over schema_id.

The schema_id is a known schema ID that can be used to select a schema from the package. As of this writing only “FDSN-v1.0” is an accepted value and uses the published schema: ExtraHeaders-FDSN-v1.0.schema-2020-12.json

Parameters:
  • schema_id (str) – ID of the known schema to use, defaults to “FDSN-v1.0”

  • schema_file (str | os.PathLike[str] | None) – Path to specific schema file to use, accepting str or any os.PathLike. Defaults to None.

Returns:

A list of jsonschema_rs.ValidationError instances, empty if no errors.

Return type:

list[JsonSchemaValidationError]

Examples

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.extra = '''{
...                "FDSN": {
...                  "Time": {
...                    "Quality": 100,
...                    "Correction": 1.234
...                  },
...                  "Flags": {
...                    "MassPositionOffscale": true
...                  }
...                },
...                "Operator": {
...                  "Battery": {
...                    "Status": "CHARGING"
...                  }
...                }}'''
>>> msr.validate_extra_headers()
[]

# INVALID headers >>> msr.extra = ‘’’{ … “FDSN”: { … “Time”: { … “Quality”: “really good”, … “Correction”: false … }, … “Flags”: { … “MassPositionOffscale”: 1.2345 … }, … “Invalid”: { … “Header”: “value not allowed in FDSN section” … } … }}’’’ >>> errors = msr.validate_extra_headers() >>> len(errors) 4

valid_extra_headers(schema_id='FDSN-v1.0', schema_file=None)[source]

Check if the extra headers are valid

The selected schema should conform to the JSON Schema 2020-12 specification: https://json-schema.org/draft/2020-12#draft-2020-12

Any specified schema_file will take precedence over schema_id.

The schema_id is a known schema ID that can be used to select a schema from the package. As of this writing only “FDSN-v1.0” is an accepted value and uses the published schema: ExtraHeaders-FDSN-v1.0.schema-2020-12.json

Parameters:
  • schema_id (str) – ID of the known schema to use, defaults to “FDSN-v1.0”

  • schema_file (str | PathLike[str] | None) – Path to specific schema file to use, defaults to None

Returns:

True if the extra headers are valid, False otherwise.

Return type:

bool

Examples

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.extra = '''{
...                "FDSN": {
...                  "Time": {
...                    "Quality": 100
...                  }
...                }
...                }'''
>>> msr.valid_extra_headers()
True
>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> msr.extra = '''{
...                "FDSN": {
...                  "Emit": {
...                    "Ytilauq": 100
...                  }
...                }
...                }'''
>>> msr.valid_extra_headers()
False
property datasamples: memoryview[Any]

Data samples as a memoryview (zero-copy access).

Returns a memoryview of the decoded data samples. This provides direct access to the internal buffer without copying data.

The view type depends on the data encoding:

  • Integer data (Steim1/2, int16/32): memoryview of 32-bit integers

  • Float32 data: memoryview of 32-bit floats

  • Float64 data: memoryview of 64-bit floats

  • Text data: memoryview of bytes

Note

The returned view is only valid while this MS3Record exists. If data is needed beyond the record’s lifetime, make a copy.

Returns:

Direct view of sample data, indexed 0 to numsamples-1

Return type:

memoryview

Examples

>>> from pymseed import MS3Record
>>> reader = MS3Record.from_file("examples/example_data.mseed", unpack_data=True)
>>> msr = reader.read()
>>> # Direct indexing (no copy)
>>> first_sample = msr.datasamples[0]
>>> last_sample = msr.datasamples[-1]
>>>
>>> # Slicing (no copy)
>>> first_ten = msr.datasamples[:10]
>>>
>>> # Copy to Python list
>>> data_list = msr.datasamples[:]
>>>
>>> # Copy to new array
>>> import array
>>> data_array = array.array('f', msr.datasamples)

See also

np_datasamples: NumPy array view (requires numpy) numsamples: Number of available samples sampletype: Type indicator (‘i’, ‘f’, ‘d’, ‘t’)

property np_datasamples: Any

Data samples as a NumPy array view (zero-copy access).

Returns a NumPy array view of the decoded data samples without copying the underlying data.

The array dtype depends on the data encoding: - Integer data (Steim1/2, int16/32): numpy.int32 - Float32 data: numpy.float32 - Float64 data: numpy.float64 - Text data: numpy dtype ‘S1’ (1-byte strings)

Returns:

1D array view of the sample data

Return type:

numpy.ndarray

Raises:

Note

Requires NumPy to be installed. The returned array is only valid while this MS3Record exists. For permanent storage, make a copy.

Examples

>>> from pymseed import MS3Record
>>> reader = MS3Record.from_file("examples/example_data.mseed", unpack_data=True)
>>> msr = reader.read()
>>> # Direct NumPy operations (no copy)
>>> import numpy as np
>>> data = msr.np_datasamples
>>> mean_value = np.mean(data)
>>> max_value = np.max(data)
>>> # Copy for permanent storage
>>> data_copy = msr.np_datasamples.copy()
>>> # Mathematical operations
>>> filtered = data * 0.5  # Creates new array

See also

datasamples: Raw memoryview access numsamples: Number of available samples sampletype: Type indicator (‘i’, ‘f’, ‘d’, ‘t’)

property datasize: int

Return size of decoded data payload in bytes

property numsamples: int

Number of data samples that have been decoded and are available.

This represents the actual number of samples accessible via datasamples or np_datasamples properties. May differ from samplecnt (which is the declared sample count in the record header) if data has not been decoded.

Returns:

Number of decoded samples (0 if no data decoded)

Return type:

int

See also

samplecnt: Sample count from record header datasamples: Access to the actual sample data

property sampletype: str | None

Return sample type code if available, otherwise None

sampletype_str()[source]

Return sample type as descriptive string

Return type:

str | None

property endtime: int

End time of the last sample as nanoseconds since Unix epoch.

Calculated from starttime, sample rate, and number of samples. For regularly sampled data: endtime = starttime + (numsamples-1)/samprate

Returns:

Nanoseconds since Unix epoch (1970-01-01T00:00:00Z)

Return type:

int

See also

starttime: Start time of first sample endtime_seconds: End time as floating-point seconds endtime_str(): Human-readable end time string

property endtime_seconds: float

Return end time as seconds since Unix/POSIX epoch

endtime_str(timeformat=TimeFormat.ISOMONTHDAY_Z, subsecond=SubSecond.NANO_MICRO_NONE)[source]

Return end time as formatted string

Returns the sentinel strings "ERROR" or "UNSET" when the underlying nanosecond timestamp is the corresponding libmseed sentinel.

Parameters:
Return type:

str

encoding_str()[source]

Human-readable description of the data encoding format.

Returns:

Descriptive string like “STEIM-2 integer compression”,

”32-bit float (IEEE single)”, "Unset" if the encoding is not set, or "Unknown" if libmseed does not recognize the encoding code.

Return type:

str

See also

encoding: Numeric encoding code

print(details=0)[source]

Print record information to stdout with configurable detail level.

Useful for debugging and inspecting record contents. Output includes metadata, timing information, and optionally sample data.

Parameters:

details (int) – Detail level for output: 0 = Basic record header information (default) 1 = All record header information

Return type:

None

unpack_data(verbose=0)[source]

Unpack the record’s data samples

This method unpacks (decodes) the data samples associated with the record if they were not decoded during the parsing process. This is useful when only specific records need to be unpacked or for delayed unpacking workflows.

Parameters:

verbose (int) – Verbosity level for diagnostic output. Default: 0

Returns:

Number of samples unpacked

Raises:

MiniSEEDError – If unpacking fails

Return type:

int

with_datasamples(data_samples, sample_type)[source]

Context manager for temporarily setting data samples with automatic cleanup.

This context manager temporarily sets data samples, counts, and type for the record and automatically restores the original state when exiting the context.

A common use case is to set data samples for creating (packing) miniSEED records, but this can be used for any purpose that requires setting data samples for a short period of time.

Parameters:
  • data_samples (Any) – One-dimensional sequence containing the data samples. Can be a list, numpy array, memoryview, or any object supporting the sequence protocol. If the value supports a memoryview, it will be used directly without copying.

  • sample_type (str) – Single character string indicating the data type (‘i’, ‘f’, ‘d’, ‘t’)

Yields:

MS3Record – The record with the temporary data samples set

Raises:

ValueError – If data_samples is not one-dimensional, or sample_type is not one of ‘i’, ‘f’, ‘d’, ‘t’.

Return type:

Iterator[MS3Record]

Examples

Setting data samples for packing:

>>> from pymseed import MS3Record, DataEncoding
>>> msr = MS3Record()
>>> msr.sourceid = "FDSN:XX_TEST__H_S_X"
>>> msr.reclen = 512
>>> msr.formatversion = 3
>>> msr.set_starttime_str("2023-01-02T01:02:03.123456789Z")
>>> msr.samprate = 100.0
>>> msr.pubversion = 1
>>> msr.encoding = DataEncoding.STEIM2

# A data array that can be used without copying (zero-copy). This is # a common case for data that is already in a bytearray, numpy array, # or other object from which a memoryview can be created. >>> import array >>> data = array.array(‘i’, [1, 2, 3, 4])

>>> output_file = "output.mseed"
>>> with msr.with_datasamples(data, 'i'):
...     print (f"Writing records for {msr.numsamples} samples of type {msr.sampletype}")
...     packed_records = msr.to_file(output_file)
Writing records for 4 samples of type i

# Setting data samples for packing from a simple list that will be copied

>>> data = [1.1, 2.6, 3.2, 4.8] # A simple list will be copied (no memoryview)
>>> with msr.with_datasamples(data, 'f'):
...     print (f"Record has {msr.numsamples} samples of type {msr.sampletype}")
Record has 4 samples of type f

# Setting text data can be a string, bytes, bytearray, or a sequence # that is converted to byte characters. Text data is always copied.

>>> text_samples = "This is a log entry"
>>> msr.sourceid = "FDSN:XX_TEST__L_O_G"
>>> msr.samprate = 0
>>> with msr.with_datasamples(text_samples, 't'):
...     print (f"Record has {msr.numsamples} samples of type {msr.sampletype}")
Record has 19 samples of type t

Note

The original record state is completely restored when exiting the context, including datasamples pointer, data size, sample counts, and sample type.

A zero-copy source is held by reference for the whole context and must not be resized within it, which would leave the record pointing at freed memory. On CPython the buffer protocol refuses the resize with BufferError; PyPy keeps no export count, so there such a resize is undefined behavior that nothing reports.

See also

MS3TraceList.add_data(): Add data samples to a trace list

generate(data_samples=None, sample_type=None, *, verbose=0)[source]

Create miniSEED record(s) using parameters from the record.

This method creates miniSEED records using the parameters (encoding, record length, etc.) in this MS3Record. Alternate data samples (and type) can be provided, otherwise the existing record data is used.

This method returns a generator that yields each miniSEED record as bytes.

Parameters:
  • data_samples (Any) – Data to pack. If None, uses existing record data. Types supported: list of int/float/str, numpy arrays, or any buffer-protocol compatible object.

  • sample_type (str | None) – Sample type indicator when providing data_samples: ‘i’ = 32-bit integer ‘f’ = 32-bit float ‘d’ = 64-bit float ‘t’ = text (1 byte per sample) Required when data_samples is provided.

  • verbose (int) – Verbosity level for diagnostic output (0=quiet, 1+=verbose)

Yields:

bytes – Each miniSEED record as it is created

Raises:

ValueError – If only one of data_samples and sample_type is provided. They must be passed together or both omitted.

Return type:

Iterator[bytes]

Examples

>>> from pymseed import MS3Record, DataEncoding
>>>
>>> # Create record template with MS3Record()
>>> msr = MS3Record()
>>> msr.sourceid = "FDSN:XX_TEST__L_H_Z"
>>> msr.set_starttime_str("2024-01-01T00:00:00Z")
>>> msr.samprate = 1
>>>
>>> # Generate miniSEED records and write to file
>>> # (See `MS3Record.to_file()` for a more convenient way to write to a file)
>>> with open('output.mseed', 'wb') as f:
...     for record in msr.generate(
...         data_samples=[1, 2, 3, 4, 5],
...         sample_type='i'
...     ):
...         f.write(record)
>>>
>>> # Generate miniSEED records and collect in a list
>>> record_list = []
>>> msr.encoding = DataEncoding.FLOAT32
>>> data_samples = [1.0, 2.1, 3.2, 4.3, 5.4]
>>> for record in msr.generate(data_samples=data_samples, sample_type='f'):
...     record_list.append(record)
>>> print(f"Generated {len(record_list)} records")
Generated 1 records

See also

MS3Record: Full record documentation

to_file(filename, *, overwrite=False, verbose=0)[source]

Write data contained in the record to a miniSEED file

Parameters:
  • filename (str | PathLike[str]) – Path to the output miniSEED file. Accepts str or any os.PathLike (e.g. pathlib.Path); other types raise TypeError. The file will be created if it doesn’t exist. Directory must already exist.

  • overwrite (bool) – If True, overwrites existing file. If False and file exists, append data to the end of the file. Default is False for safety.

  • verbose (int) – Verbosity level for libmseed output (0=quiet, 1=info, 2=detailed).

Returns:

Number of miniSEED records written to the file.

Return type:

int

Raises:
  • TypeError – If filename is not a str or os.PathLike.

  • MiniSEEDError – If the underlying libmseed library encounters an error during file writing (e.g., permission denied, disk full, invalid data).

See also

generate(): For creating record MS3Record: Full record documentation

classmethod from_file(filename, **kwargs)[source]

Create a record reader for miniSEED files.

This convenience method returns an MS3RecordReader that can iterate over all records in a miniSEED file.

Note that the objects returned by this iterator are only valid during the lifetime of the iterator. Once the iterator is exhausted, the objects are no longer valid and should not be used.

Records may be filtered with the sourceid, starttime, and endtime keyword arguments; only records matching the source ID glob pattern and/or overlapping the time window are returned. The filtering is performed inside libmseed, so non-matching records are skipped without crossing into Python and their data samples are never decoded.

Parameters:
  • filename (str | os.PathLike[str] | int) – Path to miniSEED file

  • **kwargs (Any) – Additional arguments passed to MS3RecordReader, e.g. unpack_data, sourceid, starttime, endtime, skip_not_data, validate_crc, verbose.

Returns:

Iterator over records in the file

Return type:

MS3RecordReader

Note

A filter that matches nothing yields no records rather than raising, and so does an empty file. Non-empty content that isn’t miniSEED still raises.

A file ending part way through a record, or with bytes remaining that are too few for one, raises MiniSEEDError after the records that did parse. Pass skip_not_data=True to accept such a remnant as the end of the stream.

Examples

Read every record in a file:

>>> from pymseed import MS3Record
>>> total_samples = 0
>>> for msr in MS3Record.from_file(
...     'examples/example_data.mseed', unpack_data=True
... ):
...     total_samples += msr.numsamples
>>> print(f"Total samples: {total_samples}")
Total samples: 12600

Read only the records matching a source ID and time window:

>>> records = [
...     (msr.sourceid, msr.starttime_str())
...     for msr in MS3Record.from_file(
...         "examples/example_data.mseed",
...         sourceid="FDSN:IU_COLA_00_L_H_Z",
...         starttime="2010-02-27T07:00:00Z",
...         endtime="2010-02-27T07:30:00Z",
...     )
... ]
>>> len(records)
15

A record is selected when it overlaps the window, so the first one may start before starttime:

>>> records[0]
('FDSN:IU_COLA_00_L_H_Z', '2010-02-27T06:59:01.069539Z')

See also

from_buffer(): Read from memory buffer MS3RecordReader: Full file reader documentation

classmethod from_buffer(buffer, *, unpack_data=False, sourceid=None, starttime=None, endtime=None, validate_crc=True, verbose=0)[source]

Iterate over miniSEED records in a memory buffer.

Parses miniSEED records sequentially from a bytes-like object and yields each record. All state is kept in local variables for maximum iteration speed.

Note that each yielded MS3Record shares a C struct with the generator. The record is only valid until the next next() call on the generator. If you need to retain a record beyond the current iteration step, copy the fields you need or use parse() instead.

The buffer is held by reference for the lifetime of the generator (CFFI keeps a buffer-protocol export over it). For mutable buffer types (bytearray, memoryview over a bytearray, writable numpy.ndarray), the caller must not modify the contents until iteration finishes — doing so is undefined behavior that silently corrupts the next record read and is not caught by Python or CFFI. On CPython, resizing operations (e.g. buf.extend(...), buf.clear(), del buf[i:]) are caught by the buffer protocol and raise BufferError while the generator is alive; PyPy keeps no such export count, so there a resize is undefined behavior as well. If the source must remain writable, pass an immutable copy (bytes(buf)), or close the generator (e.g. gen.close(), or let the for loop complete) before mutating.

Parameters:
  • buffer (Any) – Bytes-like object containing miniSEED data. Must support the buffer protocol (e.g. bytes, bytearray, memoryview, numpy.ndarray).

  • unpack_data (bool) – If True, decode data samples for each record. Default is False.

  • sourceid (str | None) – Source ID glob pattern to select matching records (e.g. "FDSN:IU_COLA_*"). None matches all source IDs. Default is None.

  • starttime (str | None) – Start of time window as a formatted date-time string (e.g. "2024-01-01T00:00:00Z"). Only records containing data after this time are yielded. None means open start. Default is None.

  • endtime (str | None) – End of time window as a formatted date-time string. Only records containing data before this time are yielded. None means open end. Default is None.

  • validate_crc (bool) – If True, validate CRC checksums when present (miniSEED v3 only). Default is True.

  • verbose (int) – Verbosity level for libmseed diagnostics. Default is 0.

Yields:

MS3Record – Each parsed record. Valid only until the next iteration.

Raises:
  • ValueError – If buffer does not support the buffer protocol, or if starttime or endtime is not a valid date-time string. Being a generator, this is raised on first iteration rather than at the call.

  • BufferError – If buffer is not C-contiguous.

  • MiniSEEDError – If a record cannot be parsed, or if the buffer ends part way through a record, or with bytes remaining that are too few for one; the truncated cases carry a status of MS_ENDOFFILE.

Return type:

Iterator[MS3Record]

Note

Every record header in the buffer is parsed even when a filter is active; libmseed provides no way to skip a record without first reading its header. Matching is done in C (msr3_matchselect) and data samples of rejected records are never decoded, but the per-record loop remains in Python.

Examples

>>> from pymseed import MS3Record
>>> with open('examples/example_data.mseed', 'rb') as f:
...     buffer = f.read()
>>> total_samples = 0
>>> for msr in MS3Record.from_buffer(buffer, unpack_data=True):
...     total_samples += msr.numsamples
>>> print(f"Total samples: {total_samples}")
Total samples: 12600

With source ID and time-window filtering, a record is selected when it overlaps the requested window:

>>> selected = 0
>>> for msr in MS3Record.from_buffer(
...     buffer,
...     sourceid="FDSN:IU_COLA_00_L_H_Z",
...     starttime="2010-02-27T07:00:00Z",
...     endtime="2010-02-27T07:30:00Z",
... ):
...     selected += 1
>>> print(f"Selected records: {selected}")
Selected records: 15

See also

parse(): Parse a single record from a buffer (owns the C struct) from_file(): Iterate over records in a file

classmethod from_filelike(fh, *, chunk_size=65536, unpack_data=False, sourceid=None, starttime=None, endtime=None, validate_crc=True, verbose=0)[source]

Iterate over miniSEED records from a file-like object using chunked reads.

Reads from any object with a .read(n) method (e.g. io.BytesIO, sys.stdin.buffer, a network socket file, an HTTP response body) without loading the entire content into memory first.

Note that each yielded MS3Record shares a C struct with the generator. The record is only valid until the next next() call on the generator. If you need to retain a record beyond the current iteration step, copy the fields you need or use parse() instead.

Parameters:
  • fh (Any) – A file-like object with a .read(n) method that returns bytes.

  • chunk_size (int) – Number of bytes to read per .read() call, greater than 0 and less than 1 GiB. Default is 65536.

  • unpack_data (bool) – If True, decode data samples for each record. Default is False.

  • sourceid (str | None) – Source ID glob pattern to select matching records (e.g. "FDSN:IU_COLA_*"). None matches all source IDs. Default is None.

  • starttime (str | None) – Start of time window as a formatted date-time string (e.g. "2024-01-01T00:00:00Z"). Only records containing data after this time are yielded. None means open start. Default is None.

  • endtime (str | None) – End of time window as a formatted date-time string. Only records containing data before this time are yielded. None means open end. Default is None.

  • validate_crc (bool) – If True, validate CRC checksums when present (miniSEED v3 only). Default is True.

  • verbose (int) – Verbosity level for libmseed diagnostics. Default is 0.

Yields:

MS3Record – Each parsed record. Valid only until the next iteration.

Raises:
  • TypeError – If fh has no callable .read method.

  • ValueError – If chunk_size is not greater than 0 and less than 1 GiB, or if starttime or endtime is not a valid date-time string.

  • MiniSEEDError – If a record cannot be parsed, or if the stream ends part way through a record, or with bytes remaining that are too few for one; the truncated cases carry a status of MS_ENDOFFILE.

Return type:

Iterator[MS3Record]

Note

Every record header in the stream is parsed even when a filter is active; libmseed provides no way to skip a record without first reading its header. Matching is done in C (msr3_matchselect) and data samples of rejected records are never decoded, but the per-record loop remains in Python.

Examples

>>> import io
>>> from pymseed import MS3Record
>>> with open('examples/example_data.mseed', 'rb') as f:
...     data = f.read()
>>> total_samples = 0
>>> for msr in MS3Record.from_filelike(io.BytesIO(data), unpack_data=True):
...     total_samples += msr.numsamples
>>> print(f"Total samples: {total_samples}")
Total samples: 12600

With source ID and time-window filtering, a record is selected when it overlaps the requested window:

>>> selected = 0
>>> for msr in MS3Record.from_filelike(
...     io.BytesIO(data),
...     sourceid="FDSN:IU_COLA_00_L_H_Z",
...     starttime="2010-02-27T07:00:00Z",
...     endtime="2010-02-27T07:30:00Z",
... ):
...     selected += 1
>>> print(f"Selected records: {selected}")
Selected records: 15

See also

from_buffer(): Iterate over records in a complete in-memory buffer from_file(): Iterate over records in a file

classmethod iter_records(source, **kwargs)[source]

Iterate over miniSEED records from any source.

This convenience method is a wrapper around the main record reader methods.

All keyword arguments are forwarded to the underlying method. Common kwargs shared by all three paths: unpack_data, sourceid, starttime, endtime, validate_crc, verbose. chunk_size is forwarded only for file-like sources.

Passing sourceid, starttime, and/or endtime yields only the records matching the source ID glob pattern and/or overlapping the time window. For file sources the filtering happens entirely inside libmseed; for buffer and file-like sources each record header is parsed in order to be matched, but rejected records are never decoded.

Parameters:
  • source (Any) – A file path (str / os.PathLike), an open file descriptor (non-negative int, e.g. from os.open()), a file-like object with .read(), or a bytes-like object. Negative integers raise ValueError.

  • **kwargs (Any) – Forwarded to the underlying reader method.

Yields:

MS3Record – Each parsed record.

Raises:
  • MiniSEEDError – If a record cannot be parsed, or if the source ends part way through a record.

  • TypeError – If source is not a recognised type.

  • ValueError – If source is a negative integer (not a valid fd).

Return type:

Iterator[MS3Record]

Examples

>>> record_count = 0
>>> total_samples = 0
>>> for msr in MS3Record.iter_records('examples/example_data.mseed'):
...     record_count += 1
...     total_samples += msr.samplecnt
>>> print(f"Records: {record_count}, Samples: {total_samples}")
Records: 107, Samples: 12600
>>> import io
>>> with open('examples/example_data.mseed', 'rb') as f:
...     data = f.read()
>>> for msr in MS3Record.iter_records(io.BytesIO(data)):
...     print(msr)
>>> for msr in MS3Record.iter_records(data):
...     print(msr)
classmethod parse(buffer, *, unpack_data=False, validate_crc=True, verbose=0)[source]

Parse a single miniSEED record from a buffer.

This method is designed as an optimized path to parse a single miniSEED record from a memory buffer.

Parameters:
  • buffer (Any) – Bytes-like object containing a single miniSEED record. Must support the buffer protocol (e.g. bytes, bytearray, memoryview).

  • unpack_data (bool) – If True, decode and unpack data samples. Required when the record will be repacked (e.g. format conversion). Default is False.

  • validate_crc (bool) – If True, validate the CRC checksum when present (miniSEED v3 only). Default is True.

  • verbose (int) – Verbosity level for libmseed diagnostics. Default is 0.

Returns:

Fully self-contained record instance.

Return type:

MS3Record

Raises:
  • ValueError – If buffer does not support the buffer protocol.

  • BufferError – If buffer is not C-contiguous.

  • MiniSEEDError – If the buffer does not contain a complete, valid miniSEED record.

Examples

Parse header metadata only (fastest):

>>> from pymseed import MS3Record
>>> with open('examples/example_data.mseed', 'rb') as f:
...     raw = f.read(512)  # first record
>>> msr = MS3Record.parse(raw)
>>> msr.sourceid != ''
True

Parse with data samples for repacking (v2 to v3 conversion):

>>> with open('examples/example_data.mseed', 'rb') as f:
...     raw = f.read(512)
>>> msr = MS3Record.parse(raw, unpack_data=True)
>>> msr.formatversion = 3
>>> records = list(msr.generate())
>>> len(records) > 0
True

See also

from_buffer(): Iterate over multiple records in a buffer

parse_into(buffer, *, unpack_data=False, validate_crc=True, verbose=0)[source]

Parse a miniSEED record into this existing instance, reusing the C struct.

This is an optimized alternative to parse() for high-throughput loops where the same MS3Record object is reused across many records. By passing the existing C struct pointer to msr3_parse, the library can reuse the allocation rather than free and reallocate on every call, eliminating the __init__/__del__ overhead in tight loops.

Parameters:
  • buffer (Any) – Bytes-like object containing a single miniSEED record. Must support the buffer protocol (e.g. bytes, bytearray, memoryview).

  • unpack_data (bool) – If True, decode and unpack data samples. Default is False.

  • validate_crc (bool) – If True, validate the CRC checksum when present (miniSEED v3 only). Default is True.

  • verbose (int) – Verbosity level for libmseed diagnostics. Default is 0.

Returns:

self, updated in place with the new record’s fields.

Return type:

MS3Record

Raises:
  • MiniSEEDError – If the buffer does not contain a complete, valid miniSEED record.

  • BufferError – If buffer is not C-contiguous.

  • ValueError – If buffer does not support the buffer protocol, or if this wrapper does not own its underlying C struct (e.g. it was obtained from an iterator like from_buffer(), from_filelike(), or MS3RecordReader, or it is a view into an MS3TraceList). Reparsing into a borrowed struct would silently corrupt the foreign owner’s state.

Example

>>> from pymseed import MS3Record
>>> msr = MS3Record()
>>> with open('examples/example_data.mseed', 'rb') as f:
...     buf = f.read(512)
>>> _ = msr.parse_into(buf)
>>> msr.samplecnt > 0
True
>>> msr.sourceid != ''
True

See also

parse(): Classmethod that allocates a new MS3Record per call from_buffer(): Iterate over multiple records in a buffer