Skip to content

Commit 5c92c74

Browse files
authored
add some CI ignores; finish package rename (#23)
1 parent db9032e commit 5c92c74

9 files changed

Lines changed: 126 additions & 99 deletions

File tree

pyproject.toml

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55

66
[project]
7-
name = "ilabs_streamsync"
7+
name = "streamsync"
88
authors = [
99
{ name = "Daniel McCloy", email = "dan@mccloy.info" },
1010
]
@@ -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
]
@@ -50,15 +47,15 @@ docs = [
5047
]
5148

5249
[project.urls]
53-
Homepage = "https://github.com/ilabsbrainteam/ilabs_streamsync"
54-
"Bug Tracker" = "https://github.com/ilabsbrainteam/ilabs_streamsync/issues"
55-
Discussions = "https://github.com/ilabsbrainteam/ilabs_streamsync/discussions"
56-
Changelog = "https://github.com/ilabsbrainteam/ilabs_streamsync/releases"
50+
Homepage = "https://github.com/ilabsbrainteam/streamsync"
51+
"Bug Tracker" = "https://github.com/ilabsbrainteam/streamsync/issues"
52+
Discussions = "https://github.com/ilabsbrainteam/streamsync/discussions"
53+
Changelog = "https://github.com/ilabsbrainteam/streamsync/releases"
5754

5855

5956
[tool.hatch]
6057
version.source = "vcs"
61-
build.hooks.vcs.version-file = "src/ilabs_streamsync/_version.py"
58+
build.hooks.vcs.version-file = "src/streamsync/_version.py"
6259

6360
[tool.hatch.envs.default]
6461
features = ["test"]
@@ -79,15 +76,15 @@ testpaths = [
7976

8077

8178
[tool.coverage]
82-
run.source = ["ilabs_streamsync"]
79+
run.source = ["streamsync"]
8380
report.exclude_also = [
8481
'\.\.\.',
8582
'if typing.TYPE_CHECKING:',
8683
]
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"]
@@ -96,7 +93,7 @@ disallow_untyped_defs = false
9693
disallow_incomplete_defs = false
9794

9895
[[tool.mypy.overrides]]
99-
module = "ilabs_streamsync.*"
96+
module = "streamsync.*"
10097
disallow_untyped_defs = true
10198
disallow_incomplete_defs = true
10299

@@ -135,15 +132,15 @@ ignore = [
135132
]
136133
isort.required-imports = ["from __future__ import annotations"]
137134
# Uncomment if using a _compat.typing backport
138-
# typing-modules = ["ilabs_streamsync._compat.typing"]
135+
# typing-modules = ["streamsync._compat.typing"]
139136

140137
[tool.ruff.lint.per-file-ignores]
141138
"tests/**" = ["T20"]
142139
"noxfile.py" = ["T20"]
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/ilabs_streamsync/example_script.py

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/ilabs_streamsync/streamsync.py

Lines changed: 0 additions & 47 deletions
This file was deleted.
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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from __future__ import annotations
2+
3+
import mne
4+
5+
from streamsync import StreamSync, extract_audio_from_video
6+
7+
# load an MNE raw file
8+
raw = mne.io.read_raw("")
9+
cam1 = "path/to/video"
10+
flux1 = mne.io.read_raw("")
11+
my_events = []
12+
13+
14+
subjects = ["146a", "222b"]
15+
16+
for subj in subjects:
17+
# MEG data from SQUID
18+
ss = StreamSync(raw, "STIM001")
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
25+
result = ss.do_syncing()
26+
# plot (to verify good sync)
27+
fig = ss.plot_sync()
28+
fig.savefig(...) # optional
29+
# add camera events to SQUID raw as Annotations
30+
annot = ss.add_camera_events(my_events)
31+
raw.set_annotations(annot)
32+
if result < 0.7:
33+
write_log_msg(f"subj {subj} had bad pulse syncing") # noqa: F821
34+
continue
35+
36+
# apply maxfilter
37+
# do ICA

src/streamsync/streamsync.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
15+
class StreamSync:
16+
"""Synchronize two data streams.
17+
18+
Inputs: `mne.io.Raw` files, audio files (TODO which formats?),
19+
and additional camera events.
20+
21+
Outputs: `mne.Annotations` object created from the camera events and
22+
time-warped to the timescale of the `Raw`.
23+
"""
24+
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([], [], [])
32+
33+
def add_stream(
34+
self,
35+
stream: Stream,
36+
channel: Channel,
37+
events: ArrayLike | None = None, # noqa: ARG002
38+
) -> StreamSync:
39+
"""Add a new ``Raw`` or video stream, optionally with events.
40+
41+
stream : Raw | wav
42+
An audio or FIF stream.
43+
channel : str | int | None
44+
Which channel of `stream` contains the sync pulse sequence.
45+
events : array-like | None
46+
Events associated with the stream. TODO: should they be integer sample
47+
numbers? Timestamps? Do we support both?
48+
"""
49+
pulses = self._extract_pulse_sequence_from_stream(stream, channel=channel)
50+
self.streams.append(pulses)
51+
return self
52+
53+
def _extract_pulse_sequence_from_stream(
54+
self,
55+
stream: Stream, # noqa: ARG002
56+
channel: Channel, # noqa: ARG002
57+
) -> ArrayLike:
58+
# TODO triage based on input type (e.g., if it's a Raw, pull out a stim chan,
59+
# if it's audio, just add it as-is)
60+
return np.array([]) # fake return
61+
62+
def do_syncing(self) -> float:
63+
"""Synchronize all streams with the reference stream."""
64+
# TODO (waves hands) do the hard part.
65+
# TODO spit out a report of correlation/association between all pairs of streams
66+
return 0.0
67+
68+
def plot_sync(self) -> plt.figure.Figure:
69+
return plt.figure.Figure()
70+
71+
72+
def extract_audio_from_video(path_to_video: PathLike, channel: Channel) -> ArrayLike: # noqa: ARG001
73+
"""Path can be a regex or glob to allow batch processing."""
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)