Skip to content

Commit f321c0a

Browse files
authored
Merge pull request #756 from int-brain-lab/revisions_in_tasks
allow for revisions in tasks
2 parents cc79259 + 5521ba8 commit f321c0a

File tree

8 files changed

+59
-32
lines changed

8 files changed

+59
-32
lines changed

ibllib/io/extractors/video_motion.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,12 @@ def load_data(self, download=False):
111111
self.data.camera_times = {vidio.label_from_path(url): ts for ts, url in zip(cam.data, cam.url)}
112112
else:
113113
alf_path = self.session_path / 'alf'
114-
self.data.wheel = alfio.load_object(alf_path, 'wheel', short_keys=True)
115-
self.data.trials = alfio.load_object(alf_path, 'trials')
114+
wheel_path = next(alf_path.rglob('*wheel.timestamps*')).parent
115+
self.data.wheel = alfio.load_object(wheel_path, 'wheel', short_keys=True)
116+
trials_path = next(alf_path.rglob('*trials.table*')).parent
117+
self.data.trials = alfio.load_object(trials_path, 'trials')
116118
self.data.camera_times = {vidio.label_from_path(x): alfio.load_file_content(x) for x in
117-
alf_path.glob('*Camera.times*')}
119+
alf_path.rglob('*Camera.times*')}
118120
assert all(x is not None for x in self.data.values())
119121

120122
def _set_eid_or_path(self, session_path_or_eid):
@@ -428,14 +430,16 @@ def fix_keys(alf_object):
428430
return ob
429431

430432
alf_path = self.session_path.joinpath('alf')
431-
wheel = (fix_keys(alfio.load_object(alf_path, 'wheel')) if location == 'SDSC' else alfio.load_object(alf_path, 'wheel'))
433+
wheel_path = next(alf_path.rglob('*wheel.timestamps*')).parent
434+
wheel = (fix_keys(alfio.load_object(wheel_path, 'wheel')) if location == 'SDSC'
435+
else alfio.load_object(wheel_path, 'wheel'))
432436
self.wheel_timestamps = wheel.timestamps
433437
# Compute interpolated wheel position and wheel times
434438
wheel_pos, self.wheel_time = wh.interpolate_position(wheel.timestamps, wheel.position, freq=1000)
435439
# Compute wheel velocity
436440
self.wheel_vel, _ = wh.velocity_filtered(wheel_pos, 1000)
437441
# Load in original camera times
438-
self.camera_times = alfio.load_file_content(next(alf_path.glob(f'_ibl_{self.label}Camera.times*.npy')))
442+
self.camera_times = alfio.load_file_content(next(alf_path.rglob(f'_ibl_{self.label}Camera.times*.npy')))
439443
self.camera_path = str(next(self.session_path.joinpath('raw_video_data').glob(f'_iblrig_{self.label}Camera.raw*.mp4')))
440444
self.camera_meta = vidio.get_video_meta(self.camera_path)
441445

@@ -473,8 +477,8 @@ def fix_keys(alf_object):
473477
# We attempt to load in some behavior data (trials and dlc). This is only needed for the summary plots, having
474478
# trial aligned paw velocity (from the dlc) is a nice sanity check to make sure the alignment went well
475479
try:
476-
self.trials = alfio.load_file_content(next(alf_path.glob('_ibl_trials.table*.pqt')))
477-
self.dlc = alfio.load_file_content(next(alf_path.glob(f'_ibl_{self.label}Camera.dlc*.pqt')))
480+
self.trials = alfio.load_file_content(next(alf_path.rglob('_ibl_trials.table*.pqt')))
481+
self.dlc = alfio.load_file_content(next(alf_path.rglob(f'_ibl_{self.label}Camera.dlc*.pqt')))
478482
self.dlc = likelihood_threshold(self.dlc)
479483
self.behavior = True
480484
except (ALFObjectNotFound, StopIteration):

ibllib/oneibl/registration.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import itertools
66

77
from packaging import version
8+
from requests import HTTPError
9+
810
from one.alf.files import get_session_path, folder_parts, get_alf_path
911
from one.registration import RegistrationClient, get_dataset_type
1012
from one.remote.globus import get_local_endpoint_id, get_lab_from_endpoint_id
@@ -81,17 +83,29 @@ def register_dataset(file_list, one=None, exists=False, versions=None, **kwargs)
8183
client = IBLRegistrationClient(one)
8284

8385
# Check for protected datasets
86+
def _get_protected(pr_status):
87+
if isinstance(protected_status, list):
88+
pr = any(d['status_code'] == 403 for d in pr_status)
89+
else:
90+
pr = protected_status['status_code'] == 403
91+
92+
return pr
93+
8494
# Account for cases where we are connected to cortex lab database
8595
if one.alyx.base_url == 'https://alyx.cortexlab.net':
86-
protected_status = IBLRegistrationClient(
87-
ONE(base_url='https://alyx.internationalbrainlab.org', mode='remote')).check_protected_files(file_list)
96+
try:
97+
protected_status = IBLRegistrationClient(
98+
ONE(base_url='https://alyx.internationalbrainlab.org', mode='remote')).check_protected_files(file_list)
99+
protected = _get_protected(protected_status)
100+
except HTTPError as err:
101+
if "[Errno 500] /check-protected: 'A base session for" in str(err):
102+
# If we get an error due to the session not existing, we take this to mean no datasets are protected
103+
protected = False
104+
else:
105+
raise err
88106
else:
89107
protected_status = client.check_protected_files(file_list)
90-
91-
if isinstance(protected_status, list):
92-
protected = any(d['status_code'] == 403 for d in protected_status)
93-
else:
94-
protected = protected_status['status_code'] == 403
108+
protected = _get_protected(protected_status)
95109

96110
# If we find a protected dataset, and we don't have a force=True flag, raise an error
97111
if protected and not kwargs.pop('force', False):

ibllib/pipes/tasks.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,13 @@ def assert_expected(self, expected_files, silent=False):
387387
files = []
388388
for expected_file in expected_files:
389389
actual_files = list(Path(self.session_path).rglob(str(Path(*filter(None, reversed(expected_file[:2]))))))
390+
# Account for revisions
391+
if len(actual_files) == 0:
392+
collection = expected_file[1] + '/#*' if expected_file[1] != '' else expected_file[1] + '#*'
393+
expected_revision = (expected_file[0], collection, expected_file[2])
394+
actual_files = list(
395+
Path(self.session_path).rglob(str(Path(*filter(None, reversed(expected_revision[:2]))))))
396+
390397
if len(actual_files) == 0 and expected_file[2]:
391398
everything_is_fine = False
392399
if not silent:

ibllib/pipes/video_tasks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ def _run(self, overwrite=True, run_qc=True, plot_qc=True):
506506
if exist and overwrite:
507507
_logger.warning('EphysPostDLC outputs exist and overwrite=True, overwriting existing outputs.')
508508
# Find all available DLC files
509-
dlc_files = list(Path(self.session_path).joinpath('alf').glob('_ibl_*Camera.dlc.*'))
509+
dlc_files = list(Path(self.session_path).joinpath('alf').rglob('_ibl_*Camera.dlc.*'))
510510
for dlc_file in dlc_files:
511511
_logger.debug(dlc_file)
512512
output_files = []
@@ -521,7 +521,7 @@ def _run(self, overwrite=True, run_qc=True, plot_qc=True):
521521
dlc_thresh = likelihood_threshold(dlc, 0.9)
522522
# try to load respective camera times
523523
try:
524-
dlc_t = np.load(next(Path(self.session_path).joinpath('alf').glob(f'_ibl_{cam}Camera.times.*npy')))
524+
dlc_t = np.load(next(Path(self.session_path).joinpath('alf').rglob(f'_ibl_{cam}Camera.times.*npy')))
525525
times = True
526526
if dlc_t.shape[0] == 0:
527527
_logger.error(f'camera.times empty for {cam} camera. '

ibllib/plots/figures.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -783,19 +783,15 @@ def dlc_qc_plot(session_path, one=None, device_collection='raw_video_data',
783783
assert any(data[f'{cam}_times'] is not None for cam in cameras), "No camera times data could be loaded, aborting."
784784

785785
# Load session level data
786-
for alf_object in ['trials', 'wheel', 'licks']:
786+
for alf_object, collection in zip(['trials', 'wheel', 'licks'], [trials_collection, trials_collection, 'alf']):
787787
try:
788-
if alf_object == 'licks':
789-
data[f'{alf_object}'] = alfio.load_object(session_path.joinpath('alf'),
790-
alf_object) # load locally
791-
else:
792-
data[f'{alf_object}'] = alfio.load_object(session_path.joinpath(trials_collection), alf_object) # load locally
788+
data[f'{alf_object}'] = alfio.load_object(session_path.joinpath(collection), alf_object) # load locally
793789
continue
794790
except ALFObjectNotFound:
795791
pass
796792
try:
797793
# then try from alyx
798-
data[f'{alf_object}'] = one.load_object(one.path2eid(session_path), alf_object, collection=trials_collection)
794+
data[f'{alf_object}'] = one.load_object(one.path2eid(session_path), alf_object, collection=collection)
799795
except ALFObjectNotFound:
800796
logger.warning(f"Could not load {alf_object} object, some plots have to be skipped.")
801797
data[f'{alf_object}'] = None

ibllib/qc/camera.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,8 +1137,9 @@ def load_data(self, download_data: bool = None,
11371137
alf_path = self.session_path / 'alf'
11381138
try:
11391139
assert not extract_times
1140+
cam_path = next(alf_path.rglob(f'*{self.label}Camera.times*')).parent
11401141
self.data['timestamps'] = alfio.load_object(
1141-
alf_path, f'{self.label}Camera', short_keys=True)['times']
1142+
cam_path, f'{self.label}Camera', short_keys=True)['times']
11421143
except AssertionError: # Re-extract
11431144
kwargs = dict(video_path=self.video_path, labels=self.label)
11441145
if self.sync == 'bpod':
@@ -1154,8 +1155,8 @@ def load_data(self, download_data: bool = None,
11541155
wheel_keys = ('timestamps', 'position')
11551156
try:
11561157
# glob in case wheel data are in sub-collections
1157-
alf_path = next(alf_path.rglob('*wheel.timestamps*')).parent
1158-
self.data['wheel'] = alfio.load_object(alf_path, 'wheel', short_keys=True)
1158+
wheel_path = next(alf_path.rglob('*wheel.timestamps*')).parent
1159+
self.data['wheel'] = alfio.load_object(wheel_path, 'wheel', short_keys=True)
11591160
except ALFObjectNotFound:
11601161
# Extract from raw data
11611162
if self.sync != 'bpod':

ibllib/qc/dlc.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,11 @@ def load_data(self, download_data: bool = None) -> None:
9393
alf_path = self.session_path / 'alf'
9494

9595
# Load times
96-
self.data['camera_times'] = alfio.load_object(alf_path, f'{self.side}Camera')['times']
96+
cam_path = next(alf_path.rglob(f'*{self.side}Camera.times*')).parent
97+
self.data['camera_times'] = alfio.load_object(cam_path, f'{self.side}Camera')['times']
9798
# Load dlc traces
98-
dlc_df = alfio.load_object(alf_path, f'{self.side}Camera', namespace='ibl')['dlc']
99+
dlc_path = next(alf_path.rglob(f'*{self.side}Camera.dlc*')).parent
100+
dlc_df = alfio.load_object(dlc_path, f'{self.side}Camera', namespace='ibl')['dlc']
99101
targets = np.unique(['_'.join(col.split('_')[:-1]) for col in dlc_df.columns])
100102
# Set values to nan if likelihood is too low
101103
dlc_coords = {}
@@ -106,11 +108,13 @@ def load_data(self, download_data: bool = None) -> None:
106108
self.data['dlc_coords'] = dlc_coords
107109

108110
# load stim on times
109-
self.data['stimOn_times'] = alfio.load_object(alf_path, 'trials', namespace='ibl')['stimOn_times']
111+
trial_path = next(alf_path.rglob('*trials.table*')).parent
112+
self.data['stimOn_times'] = alfio.load_object(trial_path, 'trials', namespace='ibl')['stimOn_times']
110113

111114
# load pupil diameters
112115
if self.side in ['left', 'right']:
113-
features = alfio.load_object(alf_path, f'{self.side}Camera', namespace='ibl')['features']
116+
feat_path = next(alf_path.rglob(f'*{self.side}Camera.features*')).parent
117+
features = alfio.load_object(feat_path, f'{self.side}Camera', namespace='ibl')['features']
114118
self.data['pupilDiameter_raw'] = features['pupilDiameter_raw']
115119
self.data['pupilDiameter_smooth'] = features['pupilDiameter_smooth']
116120

ibllib/tests/qc/test_task_metrics.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ def _create_test_qc_outcomes():
3131
class TestAggregateOutcome(unittest.TestCase):
3232

3333
def test_deprecation_warning(self):
34-
"""Remove TaskQC.compute_session_status_from_dict after 2024-04-01."""
34+
"""Remove TaskQC.compute_session_status_from_dict after 2024-06-01. Cherry pick commit
35+
3cbbd1769e1ba82a51b09a992b2d5f4929f396b2 for removal of this test and applicable code"""
3536
from datetime import datetime
36-
self.assertFalse(datetime.now() > datetime(2024, 4, 10), 'remove TaskQC.compute_session_status_from_dict method.')
37+
self.assertFalse(datetime.now() > datetime(2024, 6, 1), 'remove TaskQC.compute_session_status_from_dict method.')
3738
qc_dict = {'_task_iti_delays': .99}
3839
with self.assertWarns(DeprecationWarning), self.assertLogs(qcmetrics.__name__, spec.QC.WARNING):
3940
out = qcmetrics.TaskQC.compute_session_status_from_dict(qc_dict)

0 commit comments

Comments
 (0)