Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/ndi/epoch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"""

from .epoch import Epoch
from .epochprobemap import EpochProbeMap
from .epochprobemap import EpochProbeMap, build_devicestring, parse_devicestring
from .epochprobemap_daqsystem import EpochProbeMapDAQSystem
from .epochset import EpochSet
from .functions import epochrange, findepochnode
Expand All @@ -21,6 +21,8 @@
"EpochSet",
"EpochProbeMap",
"EpochProbeMapDAQSystem",
"build_devicestring",
"epochrange",
"findepochnode",
"parse_devicestring",
]
4 changes: 4 additions & 0 deletions src/ndi/epoch/epoch.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any

import pydantic
from pydantic import ConfigDict

if TYPE_CHECKING:
from ..time import ClockType
from .epochprobemap import EpochProbeMap
Expand Down Expand Up @@ -210,6 +213,7 @@ def matches_probe(
return False


@pydantic.validate_call(config=ConfigDict(arbitrary_types_allowed=True))
def is_epoch_or_empty(value: Any) -> bool:
"""
Validate that a value is an Epoch or empty.
Expand Down
4 changes: 4 additions & 0 deletions src/ndi/epoch/epochprobemap.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from dataclasses import dataclass
from typing import Any

import pydantic


@dataclass
class EpochProbeMap:
Expand Down Expand Up @@ -141,6 +143,7 @@ def __hash__(self) -> int:
return hash((self.name, self.reference, self.type))


@pydantic.validate_call
def parse_devicestring(devicestring: str) -> dict[str, str]:
"""
Parse a device string into components.
Expand All @@ -161,6 +164,7 @@ def parse_devicestring(devicestring: str) -> dict[str, str]:
}


@pydantic.validate_call
def build_devicestring(
name: str,
deviceclass: str = "",
Expand Down
3 changes: 3 additions & 0 deletions src/ndi/epoch/epochprobemap_daqsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from pathlib import Path
from typing import Any

import pydantic

from ..daq.daqsystemstring import DAQSystemString
from .epochprobemap import EpochProbeMap

Expand Down Expand Up @@ -84,6 +86,7 @@ def serialize(self) -> str:
]
)

@pydantic.validate_call
def savetofile(self, filename: str) -> None:
"""
Write this epoch probe map to a file.
Expand Down
28 changes: 17 additions & 11 deletions src/ndi/epoch/epochset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@

import hashlib
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any
from typing import Annotated, Any

import numpy as np
import pydantic
from pydantic import Field

if TYPE_CHECKING:
from ..time import ClockType
from ..time import ClockType


class EpochSet(ABC):
Expand Down Expand Up @@ -149,7 +150,8 @@ def numepochs(self) -> int:
et, _ = self.epochtable()
return len(et)

def epochclock(self, epoch_number: int) -> list[ClockType]:
@pydantic.validate_call
def epochclock(self, epoch_number: Annotated[int, Field(ge=1)]) -> list[ClockType]:
"""
Get clock types for an epoch.

Expand All @@ -163,13 +165,14 @@ def epochclock(self, epoch_number: int) -> list[ClockType]:
IndexError: If epoch_number is out of range
"""
et, _ = self.epochtable()
if epoch_number < 1 or epoch_number > len(et):
if epoch_number > len(et):
raise IndexError(f"Epoch {epoch_number} out of range (1..{len(et)})")

entry = et[epoch_number - 1]
return entry.get("epoch_clock", [])

def t0_t1(self, epoch_number: int) -> list[tuple[float, float]]:
@pydantic.validate_call
def t0_t1(self, epoch_number: Annotated[int, Field(ge=1)]) -> list[tuple[float, float]]:
"""
Get time range for an epoch.

Expand All @@ -183,13 +186,14 @@ def t0_t1(self, epoch_number: int) -> list[tuple[float, float]]:
IndexError: If epoch_number is out of range
"""
et, _ = self.epochtable()
if epoch_number < 1 or epoch_number > len(et):
if epoch_number > len(et):
raise IndexError(f"Epoch {epoch_number} out of range (1..{len(et)})")

entry = et[epoch_number - 1]
return entry.get("t0_t1", [(np.nan, np.nan)])

def epochid(self, epoch_number: int) -> str:
@pydantic.validate_call
def epochid(self, epoch_number: Annotated[int, Field(ge=1)]) -> str:
"""
Get epoch ID for an epoch number.

Expand All @@ -203,11 +207,12 @@ def epochid(self, epoch_number: int) -> str:
IndexError: If epoch_number is out of range
"""
et, _ = self.epochtable()
if epoch_number < 1 or epoch_number > len(et):
if epoch_number > len(et):
raise IndexError(f"Epoch {epoch_number} out of range (1..{len(et)})")

return et[epoch_number - 1].get("epoch_id", "")

@pydantic.validate_call
def epochnumber(self, epoch_id: str) -> int:
"""
Get epoch number for an epoch ID.
Expand Down Expand Up @@ -255,7 +260,8 @@ def matchedepochtable(

return matches

def epochtableentry(self, epoch_number: int) -> dict[str, Any]:
@pydantic.validate_call
def epochtableentry(self, epoch_number: Annotated[int, Field(ge=1)]) -> dict[str, Any]:
"""
Get a single epoch table entry.

Expand All @@ -269,7 +275,7 @@ def epochtableentry(self, epoch_number: int) -> dict[str, Any]:
IndexError: If epoch_number is out of range
"""
et, _ = self.epochtable()
if epoch_number < 1 or epoch_number > len(et):
if epoch_number > len(et):
raise IndexError(f"Epoch {epoch_number} out of range (1..{len(et)})")

return et[epoch_number - 1]
Expand Down
5 changes: 5 additions & 0 deletions src/ndi/epoch/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@

from typing import Any

import pydantic
from pydantic import ConfigDict

from ..time import ClockType


@pydantic.validate_call(config=ConfigDict(arbitrary_types_allowed=True))
def epochrange(
epochset_obj: Any,
clocktype: ClockType,
Expand Down Expand Up @@ -118,6 +122,7 @@ def _resolve_epoch_index(
raise ValueError(f"Epoch ID '{epoch}' not found")


@pydantic.validate_call(config=ConfigDict(arbitrary_types_allowed=True))
def findepochnode(
epoch_node: dict[str, Any],
epoch_node_array: list[dict[str, Any]],
Expand Down
7 changes: 4 additions & 3 deletions src/ndi/ontology/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
from __future__ import annotations

import json
from functools import lru_cache
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from typing import Any

import pydantic

from .providers import PROVIDER_REGISTRY

Expand Down Expand Up @@ -115,6 +115,7 @@ def _load_prefix_map() -> dict[str, str]:
_CACHE_MAX = 100


@pydantic.validate_call
def lookup(lookup_string: str) -> OntologyResult:
"""Look up a term in the appropriate ontology.

Expand Down
12 changes: 12 additions & 0 deletions src/ndi/ontology/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from typing import Any
from urllib.parse import quote

import pydantic

# Registry populated at module load
PROVIDER_REGISTRY: dict[str, type[OntologyProvider]] = {}

Expand All @@ -22,6 +24,7 @@ class OntologyProvider:

name: str = ""

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:
"""Look up a term by ID or name. Override in subclasses."""
from . import OntologyResult
Expand Down Expand Up @@ -49,6 +52,7 @@ class OLSProvider(OntologyProvider):
ols_ontology: str = ""
ols_prefix: str = ""

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:

prefix = prefix or self.ols_prefix
Expand Down Expand Up @@ -139,6 +143,7 @@ class OMProvider(OLSProvider):
ols_ontology = "om"
ols_prefix = "OM"

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:

# OM doesn't support numeric ID lookups
Expand Down Expand Up @@ -208,6 +213,7 @@ def _load_data(self) -> list[dict[str, str]]:
NDICProvider._data = []
return []

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:
from . import OntologyResult

Expand All @@ -230,6 +236,7 @@ class NCImProvider(OntologyProvider):
name = "NCIm"
_CUI_PATTERN = re.compile(r"^C\d{7}$")

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:
from . import OntologyResult

Expand Down Expand Up @@ -277,6 +284,7 @@ class NCBITaxonProvider(OntologyProvider):

name = "NCBITaxon"

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:
from . import OntologyResult

Expand Down Expand Up @@ -344,6 +352,7 @@ class WBStrainProvider(OntologyProvider):

name = "WBStrain"

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:
from . import OntologyResult

Expand Down Expand Up @@ -392,6 +401,7 @@ class RRIDProvider(OntologyProvider):

name = "RRID"

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:
from . import OntologyResult

Expand Down Expand Up @@ -423,6 +433,7 @@ class PubChemProvider(OntologyProvider):

name = "PubChem"

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:
from . import OntologyResult

Expand Down Expand Up @@ -541,6 +552,7 @@ def _load_ontology(self) -> dict[str, Any]:
}
return EMPTYProvider._cache

@pydantic.validate_call
def lookup_term(self, term: str, prefix: str = "") -> Any:
from ndi.fun.name_utils import name_to_variable_name

Expand Down
Loading