Skip to content

Commit c2f7f42

Browse files
committed
bunch of typing, etc, to make CIs happy-ish
1 parent 056ec39 commit c2f7f42

File tree

5 files changed

+63
-36
lines changed

5 files changed

+63
-36
lines changed

pyproject.toml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,8 @@ classifiers = [
2121
"Programming Language :: Python",
2222
"Programming Language :: Python :: 3",
2323
"Programming Language :: Python :: 3 :: Only",
24-
"Programming Language :: Python :: 3.8",
25-
"Programming Language :: Python :: 3.9",
26-
"Programming Language :: Python :: 3.10",
27-
"Programming Language :: Python :: 3.11",
2824
"Programming Language :: Python :: 3.12",
25+
"Programming Language :: Python :: 3.13",
2926
"Topic :: Scientific/Engineering",
3027
"Typing :: Typed",
3128
]
@@ -87,7 +84,7 @@ report.exclude_also = [
8784

8885
[tool.mypy]
8986
files = ["src", "tests"]
90-
python_version = "3.8"
87+
python_version = "3.12"
9188
warn_unused_configs = true
9289
strict = true
9390
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
@@ -143,7 +140,7 @@ isort.required-imports = ["from __future__ import annotations"]
143140

144141

145142
[tool.pylint]
146-
py-version = "3.8"
143+
py-version = "3.12"
147144
ignore-paths = [".*/_version.py"]
148145
reports.output-format = "colorized"
149146
similarities.ignore-imports = "yes"

src/streamsync/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
from __future__ import annotations
88

99
# from ._version import version as __version__
10-
from .streamsync import StreamSync
10+
from .streamsync import StreamSync, extract_audio_from_video
1111

12-
__all__ = ["__version__", "StreamSync"]
12+
__all__ = ["__version__", "StreamSync", "extract_audio_from_video"]

src/streamsync/example_script.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,36 @@
1-
import mne # noqa F401
1+
from __future__ import annotations
2+
3+
import mne
24

35
from streamsync import StreamSync, extract_audio_from_video
46

57
# load an MNE raw file
6-
raw = None
7-
cam1 = None
8-
flux1 = None
8+
raw = mne.io.read_raw("")
9+
cam1 = "path/to/video"
10+
flux1 = mne.io.read_raw("")
911
my_events = []
1012

1113

1214
subjects = ["146a", "222b"]
1315

1416
for subj in subjects:
15-
# construct the filename/path
16-
# load the Raw
17-
# figure out where video files are & load them
18-
audio1 = extract_audio_from_video(cam1)
19-
17+
# MEG data from SQUID
2018
ss = StreamSync(raw, "STIM001")
21-
ss.add_stream(audio1)
22-
ss.add_camera_events(my_events)
23-
ss.add_stream(flux1)
19+
# audio from camera
20+
audio1 = extract_audio_from_video(cam1, channel=2)
21+
ss.add_stream(audio1, channel=1)
22+
# MEG data from FLUX
23+
ss.add_stream(flux1, channel=127)
24+
# synchronize
2425
result = ss.do_syncing()
26+
# plot (to verify good sync)
2527
fig = ss.plot_sync()
28+
fig.savefig(...) # optional
29+
# add camera events to SQUID raw as Annotations
2630
annot = ss.add_camera_events(my_events)
2731
raw.set_annotations(annot)
28-
fig.savefig(...)
2932
if result < 0.7:
30-
write_log_msg(f"subj {subj} had bad pulse syncing, aborting") # noqa F821
33+
write_log_msg(f"subj {subj} had bad pulse syncing") # noqa: F821
3134
continue
3235

3336
# apply maxfilter

src/streamsync/streamsync.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
from __future__ import annotations
2+
3+
import os
4+
5+
import matplotlib.pyplot as plt
6+
import mne
7+
import numpy as np
8+
from numpy.typing import ArrayLike
9+
10+
type Stream = mne.io.BaseRaw | ArrayLike
11+
type Channel = str | int
12+
type PathLike = str | bytes | os.PathLike
13+
14+
115
class StreamSync:
216
"""Synchronize two data streams.
317
@@ -8,12 +22,20 @@ class StreamSync:
822
time-warped to the timescale of the `Raw`.
923
"""
1024

11-
def __init__(self, reference_object, pulse_channel):
12-
self.ref_stream = reference_object.get_chan(pulse_channel)
13-
self.sfreq = reference_object.info["sfreq"] # Hz
14-
self.streams = []
25+
def __init__(self, reference_object: Stream, pulse_channel: Channel) -> None:
26+
self.ref_stream: ArrayLike = reference_object.get_chan(pulse_channel)
27+
self.sfreq: float = reference_object.info["sfreq"] # Hz
28+
self.streams: list[Stream] = []
29+
30+
def add_camera_events(self, events: ArrayLike) -> mne.Annotations: # noqa: ARG002
31+
return mne.Annotations([], [], [])
1532

16-
def add_stream(self, stream, channel=None, events=None): # noqa ARG002
33+
def add_stream(
34+
self,
35+
stream: Stream,
36+
channel: Channel,
37+
events: ArrayLike | None = None, # noqa: ARG002
38+
) -> StreamSync:
1739
"""Add a new ``Raw`` or video stream, optionally with events.
1840
1941
stream : Raw | wav
@@ -26,22 +48,27 @@ def add_stream(self, stream, channel=None, events=None): # noqa ARG002
2648
"""
2749
pulses = self._extract_pulse_sequence_from_stream(stream, channel=channel)
2850
self.streams.append(pulses)
51+
return self
2952

30-
def _extract_pulse_sequence_from_stream(self, stream, channel):
53+
def _extract_pulse_sequence_from_stream(
54+
self,
55+
stream: Stream, # noqa: ARG002
56+
channel: Channel, # noqa: ARG002
57+
) -> ArrayLike:
3158
# TODO triage based on input type (e.g., if it's a Raw, pull out a stim chan,
3259
# if it's audio, just add it as-is)
33-
pass
60+
return np.array([]) # fake return
3461

35-
def do_syncing(self):
62+
def do_syncing(self) -> float:
3663
"""Synchronize all streams with the reference stream."""
3764
# TODO (waves hands) do the hard part.
3865
# TODO spit out a report of correlation/association between all pairs of streams
39-
pass
66+
return 0.0
4067

41-
def plot_sync(self):
42-
pass
68+
def plot_sync(self) -> plt.figure.Figure:
69+
return plt.figure.Figure()
4370

4471

45-
def extract_audio_from_video(path_to_video, channel): # noqa ARG001
72+
def extract_audio_from_video(path_to_video: PathLike, channel: Channel) -> ArrayLike: # noqa: ARG001
4673
"""Path can be a regex or glob to allow batch processing."""
47-
pass
74+
return np.array([]) # fake return

tests/test_package.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import importlib.metadata
44

5-
import ilabs_streamsync as m
5+
import streamsync as m
66

77

88
def test_version():

0 commit comments

Comments
 (0)