Skip to content

Python API reference

Auto-generated from the source docstrings. For a task-oriented walkthrough see the Python guide.

The native API:

mef3io.Reader

Reader(path: str, password: str = '', backend: str = 'cpp', n_threads: int = 0, cache=None)

Read-only interface to a MEF 3.0 session.

Times throughout are uUTC (microseconds since the Unix epoch). Windowed reads fetch only the bytes they need, so they stay cheap on huge sessions.

Parameters:

Name Type Description Default
path str

Path to the .mefd session directory, or to an uncompressed tar archive of one (name.mefd.tar, from :func:mef3io.archive_session) — tar sessions are read in place, without extraction. The suffix is enforced: anything else is refused, so a stray directory or file can never be misread as a session.

required
password str

Password for encrypted sessions. A level-2 password unlocks everything; a level-1 password reads the signal and technical metadata but leaves subject metadata locked. Empty for unencrypted sessions.

''
backend ('cpp', 'pure')

Which implementation to use. Defaults to the C++ backend; the pure backend is not yet implemented.

"cpp"
n_threads int

Worker threads for RED block decoding. 0 (default) uses all cores, 1 is serial. Output is byte-identical regardless of thread count.

0
cache str or None

Opt-in warm-start cache for channel metadata. None (default) disables it; "auto" uses the per-user OS cache directory; a path makes it persistent. Warm opens serve :attr:channels / :meth:info without touching the session tree.

None

Examples:

>>> with mef3io.Reader("session.mefd") as r:
...     x = r.read(r.channels[0], t0, t1)   # float64, NaN in gaps

channels property

channels: list[str]

Channel names in the session, sorted.

Returns:

Type Description
list of str

metadata property

metadata

Session subject/acquisition metadata as a :class:mef3io.Metadata.

Built from the first channel (metadata is session-wide). Subject fields are empty unless the reader was opened with a level-2 password.

Returns:

Type Description
Metadata

close

close() -> None

Release the backend. Optional (cleanup is automatic); present for API parity and context-manager use.

info

info(channel: str) -> dict

Channel metadata.

Parameters:

Name Type Description Default
channel str

Channel name.

required

Returns:

Type Description
dict

Keys: sampling_frequency (Hz), units_conversion_factor, units_description, start_time / end_time (uUTC), number_of_samples (stored samples — NaN gaps are not counted, so a gridded :meth:read usually returns more), recording_time_offset, n_segments, section3_available, and the section-3 subject fields (subject_name_1 / subject_name_2 / subject_id / recording_location; None without level-2 access).

read

read(channel: str, t0: Optional[int] = None, t1: Optional[int] = None, n_threads: Optional[int] = None) -> np.ndarray

Read float64 samples on the uniform sampling grid.

Parameters:

Name Type Description Default
channel str

Channel name.

required
t0 int or float

Half-open time window [t0, t1) in uUTC. Defaults span the whole channel. The number of samples returned is round((t1 - t0) * fs / 1e6).

None
t1 int or float

Half-open time window [t0, t1) in uUTC. Defaults span the whole channel. The number of samples returned is round((t1 - t0) * fs / 1e6).

None
n_threads int

Per-call override of the reader's thread count (0 = all cores, 1 = serial). None (default) uses the reader default.

None

Returns:

Type Description
ndarray

1-D float64 array on the sampling grid. Discontinuity gaps are filled with NaN; values are scaled by the channel's units-conversion factor.

See Also

read_raw : the unscaled int32 form with an explicit validity mask.

read_raw

read_raw(channel: str, t0: Optional[int] = None, t1: Optional[int] = None, n_threads: Optional[int] = None) -> dict

Read the stored int32 counts with an explicit validity mask.

Parameters:

Name Type Description Default
channel str

Channel name.

required
t0 int or float

Half-open [t0, t1) window in uUTC; defaults span the channel.

None
t1 int or float

Half-open [t0, t1) window in uUTC; defaults span the channel.

None
n_threads int

Per-call thread-count override (see :meth:read).

None

Returns:

Type Description
dict

Keys: samples (int32 ndarray, on the grid), valid (uint8 ndarray; 0 marks gap samples with no data), start_uutc, sampling_frequency, units_conversion_factor. Physical units are samples * units_conversion_factor where valid.

segments

segments(channel: str) -> list[dict]

Per-segment map of a channel — what data is where.

Read from metadata only (nothing is decoded), so it is cheap even for huge, gap-riddled sessions. Use it to locate data across large recording gaps, then :meth:toc for the block-level view within a segment.

Parameters:

Name Type Description Default
channel str

Channel name.

required

Returns:

Type Description
list of dict

One dict per segment (sorted by segment number) with keys segment, start_time / end_time (uUTC), start_sample (channel-wide index of the first sample), number_of_samples, number_of_blocks, and the on-disk path.

toc

toc(channel: str) -> list[dict]

Block-level table of contents, for seeking and viewers.

Parameters:

Name Type Description Default
channel str

Channel name.

required

Returns:

Type Description
list of dict

One dict per RED block with start_uutc, start_sample, number_of_samples, maximum_sample_value, minimum_sample_value, and discontinuity (True when the block does not continue seamlessly from the previous one).

records

records(channel: Optional[str] = None) -> list[dict]

Read records (annotations).

Parameters:

Name Type Description Default
channel str or None

Channel name for channel-level records, or None (default) for session-level records.

None

Returns:

Type Description
list of dict

One dict per record with type (e.g. "Note", "EDFA"), time (uUTC), optional text and duration.

mef3io.Writer

Writer(path: str, overwrite: bool = False, password1: str = '', password2: str = '', units: Optional[str] = None, block_length: Optional[int] = None, n_threads: int = 0, metadata=None)

Write a MEF 3.0 session.

Times throughout are uUTC (microseconds since the Unix epoch). The first write to a channel creates segment 0; later writes append in-segment (extending the existing files) unless new_segment=True.

Parameters:

Name Type Description Default
path str

Path to the .mefd session directory to create or extend (the suffix is enforced). Tar archives are read-only sessions: a .tar path raises — write a directory and pack it with :func:mef3io.archive_session.

required
overwrite bool

True deletes any existing session first. False (default) reopens an existing session for appending — state is recovered from disk, so appends work across program runs.

False
password1 str

Level-1 and level-2 passwords. MEF has no "level-1 only" files, so to encrypt a session pass both; leave both empty for no encryption.

''
password2 str

Level-1 and level-2 passwords. MEF has no "level-1 only" files, so to encrypt a session pass both; leave both empty for no encryption.

''
units str or None

Physical units label stored in metadata (e.g. "uV").

None
block_length int or None

RED block size in samples. None (default) derives it from fs (fs samples for fs >= 5000, else 10*fs).

None
n_threads int

Worker threads for RED encoding (0 = all cores, 1 = serial). Output is byte-identical regardless of thread count.

0
metadata Metadata or dict

Session-wide subject/acquisition metadata written to every channel. Also settable later via :meth:set_metadata (before writing).

None

Examples:

>>> with mef3io.Writer("session.mefd", overwrite=True, units="uV") as w:
...     w.write("ch1", data, start_uutc, fs=256.0)   # NaN marks gaps

set_metadata

set_metadata(metadata) -> None

Set session-wide subject/acquisition metadata (a :class:mef3io.Metadata, or a flat dict of fields). Call before writing; applies to every channel.

close

close() -> None

Finalize and release the writer. Called automatically on context-manager exit.

write

write(channel: str, data: ndarray, start_uutc: int, fs: float, precision: int = -1, new_segment: bool = False) -> dict

Write float data; NaN runs become discontinuity gaps.

Values are quantized to int32 counts as round(data * 10**precision) with the conversion factor 10**-precision kept in metadata. NaN samples are not stored — they read back as NaN.

Parameters:

Name Type Description Default
channel str

Channel name (created on first write).

required
data array_like

Any numeric input; coerced to float64 (lists, int arrays, float32 all accepted).

required
start_uutc int or float

Timestamp of the first sample, uUTC.

required
fs float

Sampling frequency in Hz.

required
precision int

Decimal precision for quantization. -1 (default) infers it from the data — or, when appending, reuses the segment's stored precision so the append cannot conflict.

-1
new_segment bool

Force a fresh segment instead of appending in-segment.

False

Returns:

Type Description
dict

samples_written, blocks, gaps_skipped, segment.

Raises:

Type Description
RuntimeError

On an append conflict (fs / conversion-factor mismatch, or data starting before the segment's end).

write_int32

write_int32(channel: str, data: ndarray, ufact: float, start_uutc: int, fs: float, valid: Optional[ndarray] = None, new_segment: bool = False) -> dict

Write integer counts verbatim with a conversion factor (bit-exact).

The primitive path: counts are stored exactly as given, with ufact (e.g. an amplifier's volts-per-bit) in metadata. Physical units on read are counts * ufact.

Parameters:

Name Type Description Default
channel str

Channel name (created on first write).

required
data array_like of int

Integer counts (any integer width). Stored bit-exact.

required
ufact float

Conversion factor from counts to physical units.

required
start_uutc int or float

Timestamp of the first sample, uUTC.

required
fs float

Sampling frequency in Hz.

required
valid array_like or None

Same length as data; any numeric/bool mask where nonzero marks a real sample and zero a discontinuity gap. None = all valid.

None
new_segment bool

Force a fresh segment instead of appending in-segment.

False

Returns:

Type Description
dict

samples_written, blocks, gaps_skipped, segment.

Raises:

Type Description
TypeError

If data is floating-point (use :meth:write for float data — counts are never silently rounded here).

ValueError

If any value is outside the int32 range (it would wrap).

RuntimeError

On an append conflict.

write_annotations

write_annotations(annotations, channel: Optional[str] = None) -> None

Write records (annotations).

Replaces the records at the given level. In encrypted sessions record bodies are level-2 encrypted.

Parameters:

Name Type Description Default
annotations iterable of dict or pandas.DataFrame

Each record needs time (uUTC); type defaults to "Note"; text and duration are optional. A DataFrame with those columns is accepted.

required
channel str or None

Channel name for channel-level records, or None (default) for session-level records.

None

mef3io.archive_session

archive_session(session_path, tar_path: Optional[str] = None, overwrite: bool = False) -> str

Pack a session directory into a single uncompressed tar archive.

The archive (conventionally name.mefd.tar) is a plain ustar file: :class:Reader opens it directly — no extraction — and any tar tool (tar -xf) reproduces the original directory. Because it is uncompressed, windowed reads still fetch only the byte ranges they need. The source directory is left untouched; output is deterministic, so archiving the same session twice yields identical bytes. Tar sessions are read-only: :class:Writer refuses .tar paths.

Parameters:

Name Type Description Default
session_path str or path - like

The .mefd session directory to pack (the suffix is enforced).

required
tar_path str

Target archive path; must end .mefd.tar. Default derives <session_path>.tar (name.mefd becomes name.mefd.tar).

None
overwrite bool

Replace an existing target archive. Default False (an existing target raises).

False

Returns:

Type Description
str

Path of the created archive.

Examples:

>>> tar = mef3io.archive_session("session.mefd")
>>> with mef3io.Reader(tar) as r:
...     x = r.read(r.channels[0])

mef3io.extract_session

extract_session(tar_path, dest_dir: Optional[str] = None, overwrite: bool = False) -> str

Unpack a session archive back into a .mefd directory.

The inverse of :func:archive_session — after extraction the directory is a normal writable session again. The session root inside the archive is stripped, so dest_dir becomes the session directory itself; archives from foreign tar tools work too. A failed extraction never leaves a half-written directory behind.

Parameters:

Name Type Description Default
tar_path str or path - like

The session archive to unpack; must end .mefd.tar.

required
dest_dir str

Target directory; must end .mefd. Default strips the .tar suffix (name.mefd.tar becomes name.mefd next to the archive).

None
overwrite bool

Replace an existing target directory. Default False (an existing target raises).

False

Returns:

Type Description
str

Path of the extracted session directory.

Examples:

>>> session = mef3io.extract_session("session.mefd.tar")
>>> with mef3io.Writer(session) as w:      # writable again
...     w.write("ch1", more_data, t, fs=256.0)

Metadata objects

mef3io.Metadata dataclass

Metadata(subject: Subject = Subject(), acquisition: Acquisition = Acquisition())

Session-wide metadata: a :class:Subject and an :class:Acquisition block. Written to every channel; on read, reflects the first channel.

to_dict

to_dict() -> dict

Nested plain-dict view: {"subject": {...}, "acquisition": {...}}.

from_info classmethod

from_info(info: dict) -> 'Metadata'

Build a Metadata from a :meth:Reader.info dict. Subject fields are empty when the reader lacks level-2 access (section3_available).

mef3io.Subject dataclass

Subject(name_1: str = '', name_2: str = '', id: str = '', recording_location: str = '', gmt_offset: int = 0)

Subject / recording-context metadata (MEF section 3, level-2 encrypted).

mef3io.Acquisition dataclass

Acquisition(session_description: str = '', channel_description: str = '', reference_description: str = '', acquisition_channel_number: int = 1, low_frequency_filter: float = _UNSET_HZ, high_frequency_filter: float = _UNSET_HZ, notch_filter: float = _UNSET_HZ, line_frequency: float = _UNSET_HZ)

Descriptive / acquisition metadata (MEF section 2, level-1 encrypted).

Filter settings default to -1.0 meaning "not recorded".

Legacy mef_tools compatibility

Drop-in replacements for mef_tools.iofrom mef3io import MefReader, MefWriter. Same call shapes and defaults as the legacy classes; see the legacy comparison for the measured differences.

mef3io.compat.MefReader

MefReader(session_path: str, password2: Optional[str] = None)

mef_tools.io.MefReader-compatible reader.

session_path may also be an uncompressed tar archive of a session (name.mefd.tar, see :func:mef3io.archive_session).

mef3io.compat.MefWriter

MefWriter(session_path, overwrite=False, password1=None, password2=None, verbose=False, metadata=None)

mef_tools.io.MefWriter-compatible writer.

Like the legacy writer, appends extend the channel's last segment in place (in-segment append); pass new_segment=True to start a fresh segment.

Metadata works two ways: mutate the legacy section3_dict / section2_ts_dict (e.g. w.section3_dict['subject_ID'] = 'Smith') as with mef_tools, or use the modern object via set_metadata / the metadata= argument (mef3io.Metadata).

mef_block_len property writable

mef_block_len

RED block length in samples (None = derive from fs, like legacy).

max_nans_written property writable

max_nans_written: int

Kept for legacy compatibility. mef3io always splits data on NaN runs (never stores NaN as values), i.e. it behaves like the legacy writer's recommended setting of 0; other values are accepted and ignored.

record_offset property writable

record_offset: int

Kept for legacy compatibility. mef3io writes records with a zero recording-time offset (annotation times round-trip unchanged either way); non-zero values are accepted and ignored.

set_metadata

set_metadata(metadata) -> None

Set session-wide subject/acquisition metadata (a :class:mef3io.Metadata or a flat dict). Applied on the next write.

get_mefblock_len

get_mefblock_len(fs: float) -> int

Block length that will be used for data at fs (legacy formula).