Bases
timenet_connectors.bases ¶source
Reusable connector base classes.
edf ¶source
Read EDF and EDF+ files for the connectors that build datasets from them.
reader ¶source
Read the EDF container: the header of a file, and one data record from it.
EDF holds an ASCII header and then data records of 16-bit integers. One record holds the samples of every signal for one stretch of time, one signal after the other. Signals of different rates therefore hold a different count of samples in the same record.
This module parses no bytes. edfio does that. A connector that reads EDF declares
edfio in its requirements.txt.
:class:EdfHeader and :class:EdfFile are the boundary: edfio types stay inside this
file, thus a later change of library does not reach the modules that call it.
EdfHeader ¶source
build_signal_loader ¶source
Build the lazy loader of one signal.
The loader holds the open file, thus the signals of one recording share one open file and one memory map. A build keeps every file it opened open until the writer has called the loaders.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
EdfFile
|
The open file, from :func: |
required |
index
|
int
|
The signal, in the order of the header. |
required |
Returns:
| Type | Description |
|---|---|
Callable[[], Array]
|
A loader that takes no argument and gives the signal in physical units. |
compute_signal_end_microseconds ¶source
Give where the recorded signals stop, in microseconds from the first sample.
The timeline starts at zero, so this is both the length of the signals and the exclusive end of the timeline. An annotation is measured against this bound.
Every record of the file follows the one before it with no gap, because :func:open_edf
refuses a discontinuous file. The records therefore multiply out to the whole timeline.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
header
|
EdfHeader
|
The header of a signal file. |
required |
Returns:
| Type | Description |
|---|---|
int
|
|
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If that product is not a whole number of microseconds. |
convert_digital_to_physical ¶source
convert_digital_to_physical(
digital: ndarray,
*,
digital_min: float,
digital_max: float,
physical_min: float,
physical_max: float,
) -> ndarray
Convert stored integers into the physical unit that the header names.
EDF stores no volts. It stores counts, and the header of each file states which range of physical values those counts cover::
gain = (physical_max - physical_min) / (digital_max - digital_min)
physical = (digital - digital_min) * gain + physical_min
The four values must come from the header of the file that holds these counts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
digital
|
ndarray
|
The stored counts. |
required |
digital_min
|
float
|
The smallest count that the signal writes. |
required |
digital_max
|
float
|
The largest count that the signal writes. |
required |
physical_min
|
float
|
The value that |
required |
physical_max
|
float
|
The value that |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
The values in the physical unit of the signal, as float32. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the digital range is empty, because it then gives no scale. |
open_edf ¶source
Open an EDF file, read its header, and map its records.
Reading is lazy: a caller that wants the header alone reads no signal bytes. Open a file
one time and pass the result to :func:read_signal, so its header is parsed once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
The |
required |
Returns:
| Type | Description |
|---|---|
EdfFile
|
The open file, with its header. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the file is not readable as EDF, if it is shorter than the records that its own header states, if it is discontinuous, or if it states no start date. |
read_annotations ¶source
read_annotations(
file: EdfFile,
) -> tuple[EdfAnnotation, ...]
Read every annotation of an EDF+ file, in file order.
An EDF+ file states an onset in seconds as text. Parsing that text with
:class:~decimal.Decimal keeps the onset the file states; a float would move it.
Each data record opens with an empty-text annotation that only timestamps the record.
if annotation.text drops those.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
EdfFile
|
The open file that holds the annotations, from :func: |
required |
Returns:
| Name | Type | Description |
|---|---|---|
One |
tuple[EdfAnnotation, ...]
|
class: |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If an onset or a duration is not a whole number of microseconds. |
read_record ¶source
Read one data record, and give one array for each signal.
The arrays have different lengths when the signals have different rates.
Reading one record reads one record. It does not read the signals it slices, thus a caller that walks a recording record by record never holds the whole recording.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
EdfFile
|
The open file, from :func: |
required |
index
|
int
|
The record to read, counted from zero. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ndarray, ...]
|
One array for each signal, in the order of the header, in physical units. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the file holds no record with this index. |
read_signal ¶source
Read one whole signal, from its first sample to its last.
Reading one signal does not read the others.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
EdfFile
|
The open file, from :func: |
required |
index
|
int
|
The signal, counted from zero, in the order of the header. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Every sample of that signal, in physical units. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the file holds no signal with this index. |
timeseries ¶source
Turn the signals of one recording into :class:~timenet.dataset.TimeSeries.
The caller passes the signal-to-spec table and the loader factory, thus this module holds nothing of this dataset and reads no sample. Every other attribute comes from the header.
build ¶source
build(
record_id: str,
file: EdfFile,
specs: Mapping[str, TimeSeriesSpec],
*,
loader: Callable[[EdfFile, int], Callable[[], Array]],
) -> tuple[TimeSeries, ...]
Give one time series for each signal that the header of a recording names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_id
|
str
|
The id of the record these signals belong to, from |
required |
file
|
EdfFile
|
Its open PSG file, from :func: |
required |
specs
|
Mapping[str, TimeSeriesSpec]
|
The table of the release, from a signal name to its spec. |
required |
loader
|
Callable[[EdfFile, int], Callable[[], Array]]
|
Builds the lazy loader of one signal, from the open file and a signal index. |
required |
Returns:
| Type | Description |
|---|---|
tuple[TimeSeries, ...]
|
One time series for each signal, in the order of the header. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the header names a signal that the spec table does not hold. |
excel ¶source
Read a legacy .xls workbook, and decode the cell values it gives back.
A connector whose source ships a spreadsheet opens it with :func:read_table_rows and gets the
rows of the first sheet. The cells come back as the workbook states them, so nothing here knows
what a column means. The connector states that.
The decoders cover what Excel itself states about a cell and nothing more. A whole number is a whole number in every workbook, and Excel writes a bare time as the fraction of a day past midnight in every workbook. A code whose meaning changes from one sheet to the next belongs to the connector that reads that sheet.
Each decoder takes the workbook name and the row number so that its error names the cell a reader has to go and look at.
decode_day_fraction_as_time ¶source
Convert an Excel day fraction into a time of day.
Excel stores a bare time as the fraction of a day past midnight, so 0.5 is 12:00:00 and a fraction below 0.5 is a time after midnight and not an error.
A string reaches this function only by accident. A column that has become text is a workbook the caller does not know.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cell
|
object
|
The value of the cell, as the workbook states it. |
required |
workbook
|
str
|
The name of the workbook, for the error message. |
required |
row_number
|
int
|
The row of the sheet, counted from 1, for the error message. |
required |
Returns:
| Type | Description |
|---|---|
time
|
The clock time that the fraction states, to the second. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the cell holds no number, or a number outside 0 up to 1. |
decode_whole_number ¶source
Decode the whole number that a cell holds.
Excel writes every number as a float, so a whole number reaches this as 44.0. A cell that
holds a fraction, a bool or text states no whole number and raises.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cell
|
object
|
The value of the cell, as the workbook states it. |
required |
field
|
str
|
The name of the column, for the error message. |
required |
workbook
|
str
|
The name of the workbook, for the error message. |
required |
row_number
|
int
|
The row of the sheet, counted from 1, for the error message. |
required |
Returns:
| Type | Description |
|---|---|
int
|
The value as a whole number. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the cell holds no whole number. |
read_table_rows ¶source
Open a workbook and give every row of its first sheet, header rows included.
This gives the cells as the workbook states them and decodes nothing.
A workbook can carry more than one sheet. This takes the first and searches for no sheet by name, because the first sheet is where a source that ships one table puts it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
The |
required |
Returns:
| Type | Description |
|---|---|
list[tuple[object, ...]]
|
One tuple of cell values for each row of the first sheet, in sheet order. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the file does not open as a workbook, or holds no sheet. |
huggingface ¶source
A reusable base for connectors that pull rows from a HuggingFace Hub dataset.
Subclasses set HF_REPO, ship a dataset.yaml card beside the connector, and implement convert().
Downloads read the Hub's auto-generated parquet ref. The Hub produces that ref for public and gated datasets.
huggingface_hub is declared in the connector's requirements.txt and installed into the environment the
build runs in; the base imports it lazily, which is what keeps --no-isolation usable. The base reads
HF_TOKEN from the environment, so gated datasets work with no extra wiring.
Fully private datasets have no auto-parquet ref, and this base does not support them.
BaseHuggingFaceConnector ¶source
Bases: BaseConnector[dict[str, Any]], ABC
Base class for HuggingFace-backed connectors. Rows are plain dicts (one per dataset row).
CARD
class-attribute
¶
Optional explicit path to the dataset card YAML. When None (the default), the connector
reads the card from dataset.yaml in its own folder.
values_backend
class-attribute
instance-attribute
¶
values_backend: str = 'parquet'
Default storage backend for this connector's values plane.
convert
abstractmethod
¶
convert(raw_refs: list[TRaw]) -> TimeFDataset
Parse raw references and populate a :class:~timenet.dataset.TimeFDataset.
CPU-bound: no network I/O. Attach time-series values as lazy loaders instead of materializing them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_refs
|
list[TRaw]
|
The references returned by :meth: |
required |
Returns:
| Type | Description |
|---|---|
TimeFDataset
|
The populated dataset. |
download ¶source
Download the repo's auto-converted parquet file(s) and return their rows.
Reads the Hub's refs/convert/parquet branch (see :attr:PARQUET_REVISION), so it handles any
source format the same way. For very large datasets the Hub conversion can be partial.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache_dir
|
Path
|
Directory where the connector caches Hub files. |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
One dict per row across all parquet files. |
Raises:
| Type | Description |
|---|---|
ImportError
|
If |
TimeNetDatasetNotFoundError
|
If the revision holds no parquet files, or they hold no rows. |
download_async
async
¶
Async variant of :meth:download for connectors whose downloads are I/O-bound.
Override this to fetch artifacts concurrently, for example with the connector HTTP download
helpers. The default :meth:download runs it for you. Implement exactly one of the two.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache_dir
|
Path
|
Directory to write downloaded files into (created by the engine). |
required |
Returns:
| Type | Description |
|---|---|
list[TRaw]
|
Raw references passed directly to :meth: |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If a subclass overrides neither :meth: |
metadata ¶
metadata() -> DatasetMetadata
Return the dataset's descriptive identity, loaded and validated from its card YAML.
Reads the card by convention (dataset.yaml beside the connector, unless :attr:CARD
overrides it). Its dataset_id must match the id used to register or build the connector.
Returns:
| Type | Description |
|---|---|
DatasetMetadata
|
The dataset's :class: |
physionet ¶source
A reusable base class for connectors that read WFDB records from PhysioNet.
A subclass downloads a PhysioNet database archive with :func:~timenet_connectors.download.ensure_archive
and reads the records. Headers are parsed straight from the .hea text, and format-16 signals are read
directly from the .dat with NumPy; wfdb is used only as a fallback for signal formats the direct
reader does not handle. wfdb is declared in the connector's requirements.txt and installed into the
environment the build runs in, and the base class imports it lazily, so --no-isolation stays usable and
a build that never reaches the fallback needs nothing extra.
BasePhysioNetConnector ¶source
Bases: BaseConnector[TRaw], ABC
The base class for PhysioNet-backed connectors that read WFDB records.
CARD
class-attribute
¶
Optional explicit path to the dataset card YAML. When None (the default), the connector
reads the card from dataset.yaml in its own folder.
values_backend
class-attribute
instance-attribute
¶
values_backend: str = 'parquet'
Default storage backend for this connector's values plane.
convert
abstractmethod
¶
convert(raw_refs: list[TRaw]) -> TimeFDataset
Parse raw references and populate a :class:~timenet.dataset.TimeFDataset.
CPU-bound: no network I/O. Attach time-series values as lazy loaders instead of materializing them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_refs
|
list[TRaw]
|
The references returned by :meth: |
required |
Returns:
| Type | Description |
|---|---|
TimeFDataset
|
The populated dataset. |
download ¶
Fetch or discover raw source files and return lightweight references to them.
I/O only: no parsing, no array work. Must be idempotent for a given cache_dir. Override
this for a synchronous connector. For an I/O-bound one, override :meth:download_async
instead and leave this default, which drives it to completion, since the engine calls
connectors synchronously.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache_dir
|
Path
|
Directory to write downloaded files into (created by the engine). |
required |
Returns:
| Type | Description |
|---|---|
list[TRaw]
|
Raw references passed directly to :meth: |
download_async
async
¶
Async variant of :meth:download for connectors whose downloads are I/O-bound.
Override this to fetch artifacts concurrently, for example with the connector HTTP download
helpers. The default :meth:download runs it for you. Implement exactly one of the two.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache_dir
|
Path
|
Directory to write downloaded files into (created by the engine). |
required |
Returns:
| Type | Description |
|---|---|
list[TRaw]
|
Raw references passed directly to :meth: |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If a subclass overrides neither :meth: |
metadata ¶
metadata() -> DatasetMetadata
Return the dataset's descriptive identity, loaded and validated from its card YAML.
Reads the card by convention (dataset.yaml beside the connector, unless :attr:CARD
overrides it). Its dataset_id must match the id used to register or build the connector.
Returns:
| Type | Description |
|---|---|
DatasetMetadata
|
The dataset's :class: |
WfdbHeader ¶source
Bases: NamedTuple
The header fields a PhysioNet connector reads, parsed straight from the .hea text.
dat_names/formats/gains/baselines are per signal, in signal order; the direct
.dat reader uses them to turn raw ADC samples into physical units.