Errors and warnings

Exception hierarchy

All public errors derive from ecgfeat.ECGInputError, which derives from ValueError. Code that already catches ValueError keeps working; catch ECGInputError to handle only this package's errors.

ValueError
└── ECGInputError                     base class of every public error
    ├── SignalShapeError              array rank, orientation, length, non-finite values
    ├── LeadNameError                 missing, duplicate or non-canonical lead names
    ├── SamplingRateError             invalid sampling rate or internal rate
    ├── AmplitudeUnitError            unsupported amplitude unit
    ├── ConfigurationError            unsupported method or configuration value
    ├── RecordValidationError         a record violates the schema or its invariants
    │   └── SidecarError              a sidecar is missing, altered or inconsistent
    ├── RecordIdentityError           an address targets another record or schema version
    ├── AddressSyntaxError            malformed address or JSON pointer
    ├── AddressNotFoundError          the pointer does not exist in the record
    ├── MeasurementNotFoundError      the measurement is not published in this record
    ├── MeasurementSelectorError      invalid lead or beat selector
    ├── ComputationInvariantError     no trustworthy record could be built
    └── ecgfeat.viz.VisualizationInputError   signal/record mismatch or bad selector in a plot

All of these are importable from ecgfeat (except VisualizationInputError, which lives in ecgfeat.viz).

Error codes

Every error has a stable, machine-readable code, a message and optional details. Branch on code, not on the message text:

import numpy as np
from ecgfeat import ecg_record, ECGInputError, LeadNameError

signal = np.load("ecg.npy")
try:
    ecg_record(signal, sampling_rate=500, lead_names=["I", "II", "III", "AVR", "aVL", "aVF",
                                                      "V1", "V2", "V3", "V4", "V5", "V6"])
except LeadNameError as exc:
    print(exc.code)          # standard_lead_contract ("AVR" is not canonical)
    print(exc.to_dict())     # {'code': 'standard_lead_contract', 'message': '...', 'details': {}}
except ECGInputError as exc:
    print("other input problem:", exc.code)

Common codes:

Code Raised by Meaning
invalid_signal_shape, invalid_signal_type input not a numeric 2-D array
signal_lead_count_mismatch input row count differs from the number of lead names (often a transposed array)
record_too_short, empty_signal input less than 1 second, or no samples
nonfinite_signal input NaN or infinity in the signal
invalid_sampling_rate input below 100 Hz or not finite
invalid_lead_names input empty or duplicate names
standard_lead_contract input standard mode without exactly the twelve canonical leads
limited_lead_count input limited mode outside 1–8 channels
unsupported_amplitude_unit input unit other than mV or µV
invalid_input_mode, input_mode_mismatch configuration unknown mode, or config and call disagree
unknown_method configuration unsupported method
invalid_profile emit, serialization profile other than summary, all, debug
engine_version_mismatch import of the engine (EngineVersionError) the installed ecg-records-engine is of another minor version, or needs a newer ecg-records
engine_too_old import of the engine (EngineVersionError) the installed ecg-records-engine is older than this ecg-records needs (0.3.2 needs engine 0.3.2+): pip install -U "ecg-records[engine]", or keep the previous shell
record_build_failed measurement internal failure (ComputationInvariantError)
invalid_record_json, duplicate_json_member reading not valid JSON, or a member appears twice
invalid_record_contract reading a structural or cross-field invariant is violated
validation_above_registry reading a field claims a better validation tier than the registry allows
profile_data_unavailable serialization asked to serialize a larger profile than the record holds
sidecar_missing, invalid_sidecar reading sidecar absent, altered or inconsistent
measurement_not_found query name unknown or not in this profile
invalid_lead_selector, invalid_beat_selector query lead or beat missing or unknown
invalid_record_address, invalid_json_pointer addresses malformed address or pointer
record_identity_mismatch addresses the address names another record
address_not_found addresses the pointer is not in the record

Warnings

Warning Base classes Meaning
ECGWarning UserWarning base class of actionable, non-fatal warnings from this package
ECGCompatibilityWarning ECGWarning a legacy compatibility behaviour was used
ECGDeprecationWarning FutureWarning, ECGWarning a legacy API is scheduled for removal (no earlier than 0.3.0)

ECGDeprecationWarning subclasses FutureWarning, so Python shows it by default: legacy calls stay visible in scripts, not only in test runs. To turn legacy usage into errors while migrating:

import warnings
from ecgfeat import ECGDeprecationWarning

warnings.simplefilter("error", ECGDeprecationWarning)

Or run your test suite with python -W error::FutureWarning. See the migration guide for replacements.