Skip to content

Commit 634e9db

Browse files
committed
Merge branch 'release/2.32.5'
2 parents 6509ed4 + 40088c2 commit 634e9db

File tree

6 files changed

+45
-12
lines changed

6 files changed

+45
-12
lines changed

ibllib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
import warnings
44

5-
__version__ = '2.32.4'
5+
__version__ = '2.32.5'
66
warnings.filterwarnings('always', category=DeprecationWarning, module='ibllib')
77

88
# if this becomes a full-blown library we should let the logging configuration to the discretion of the dev

ibllib/io/session_params.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ def merge_params(a, b, copy=False):
169169
if k == 'sync':
170170
assert k not in a or a[k] == b[k], 'multiple sync fields defined'
171171
if isinstance(b[k], list):
172-
prev = a.get(k, [])
172+
prev = list(a.get(k, []))
173173
# For procedures and projects, remove duplicates
174-
to_add = b[k] if k == 'tasks' else set(prev) ^ set(b[k])
174+
to_add = b[k] if k == 'tasks' else set(b[k]) - set(prev)
175175
a[k] = prev + list(to_add)
176176
elif isinstance(b[k], dict):
177177
a[k] = {**a.get(k, {}), **b[k]}

ibllib/oneibl/registration.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def register_session(self, ses_path, file_list=True, projects=None, procedures=N
221221
# assert len({md['IBLRIG_VERSION_TAG'] for md in settings}) == 1
222222

223223
users = []
224-
for user in filter(None, map(lambda x: x.get('PYBPOD_CREATOR'), settings)):
224+
for user in filter(lambda x: x and x[1], map(lambda x: x.get('PYBPOD_CREATOR'), settings)):
225225
user = self.assert_exists(user[0], 'users') # user is list of [username, uuid]
226226
users.append(user['username'])
227227

@@ -246,7 +246,7 @@ def register_session(self, ses_path, file_list=True, projects=None, procedures=N
246246
if poo_counts:
247247
json_field['POOP_COUNT'] = int(sum(poo_counts))
248248

249-
if not session: # Create session and weighings
249+
if not len(session): # Create session and weighings
250250
ses_ = {'subject': subject['nickname'],
251251
'users': users or [subject['responsible_user']],
252252
'location': settings[0]['PYBPOD_BOARD'],
@@ -273,9 +273,13 @@ def register_session(self, ses_path, file_list=True, projects=None, procedures=N
273273
self.register_weight(subject['nickname'], md['SUBJECT_WEIGHT'],
274274
date_time=md['SESSION_DATETIME'], user=user)
275275
else: # if session exists update a few key fields
276-
data = {'procedures': procedures, 'projects': projects}
276+
data = {'procedures': procedures, 'projects': projects,
277+
'n_correct_trials': n_correct_trials, 'n_trials': n_trials}
277278
if task_protocols:
278279
data['task_protocol'] = '/'.join(task_protocols)
280+
if end_time:
281+
data['end_time'] = self.ensure_ISO8601(end_time)
282+
279283
session = self.one.alyx.rest('sessions', 'partial_update', id=session_id[0], data=data)
280284
if json_field:
281285
session['json'] = self.one.alyx.json_field_update('sessions', session['id'], data=json_field)
@@ -401,14 +405,16 @@ def _get_session_times(fn, md, ses_data):
401405
"""
402406
if isinstance(md, dict):
403407
start_time = _start_time = isostr2date(md['SESSION_DATETIME'])
408+
end_time = isostr2date(md['SESSION_END_TIME']) if md.get('SESSION_END_TIME') else None
404409
else:
405410
start_time = isostr2date(md[0]['SESSION_DATETIME'])
406411
_start_time = isostr2date(md[-1]['SESSION_DATETIME'])
412+
end_time = isostr2date(md[-1]['SESSION_END_TIME']) if md[-1].get('SESSION_END_TIME') else None
407413
assert isinstance(ses_data, (list, tuple)) and len(ses_data) == len(md)
408414
assert len(md) == 1 or start_time < _start_time
409415
ses_data = ses_data[-1]
410-
if not ses_data:
411-
return start_time, None
416+
if not ses_data or end_time is not None:
417+
return start_time, end_time
412418
c = ses_duration_secs = 0
413419
for sd in reversed(ses_data):
414420
ses_duration_secs = (sd['behavior_data']['Trial end timestamp'] -

ibllib/tests/test_io.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,23 @@ def test_get_collections_repeat_protocols(self):
555555
collections = session_params.get_collections(tasks, flat=True)
556556
self.assertEqual(collections, {'raw_passive_data_bis', 'raw_passive_data', 'raw_behavior_data'})
557557

558+
def test_merge_params(self):
559+
"""Test for ibllib.io.session_params.merge_params functions."""
560+
a = self.fixture
561+
b = {'procedures': ['Imaging', 'Injection'], 'tasks': [{'fooChoiceWorld': {'collection': 'bar'}}]}
562+
c = session_params.merge_params(a, b, copy=True)
563+
self.assertCountEqual(['Imaging', 'Behavior training/tasks', 'Injection'], c['procedures'])
564+
self.assertCountEqual(['passiveChoiceWorld', 'ephysChoiceWorld', 'fooChoiceWorld'], (list(x)[0] for x in c['tasks']))
565+
# Ensure a and b not modified
566+
self.assertNotEqual(set(c['procedures']), set(a['procedures']))
567+
self.assertNotEqual(set(a['procedures']), set(b['procedures']))
568+
# Test without copy
569+
session_params.merge_params(a, b, copy=False)
570+
self.assertCountEqual(['Imaging', 'Behavior training/tasks', 'Injection'], a['procedures'])
571+
# Test assertion on duplicate sync
572+
b['sync'] = {'foodaq': {'collection': 'raw_sync_data'}}
573+
self.assertRaises(AssertionError, session_params.merge_params, a, b)
574+
558575

559576
class TestRawDaqLoaders(unittest.TestCase):
560577
"""Tests for raw_daq_loaders module"""

ibllib/tests/test_oneibl.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -429,16 +429,20 @@ def test_registration_session(self):
429429
query_type='remote')[0]
430430
ses_info = self.one.alyx.rest('sessions', 'read', id=eid)
431431
self.assertTrue(ses_info['procedures'] == ['Behavior training/tasks'])
432-
self.one.alyx.rest('sessions', 'delete', id=eid)
433-
# re-register the session as unknown protocol this time
432+
# re-register the session as unknown protocol, this time without removing session first
434433
self.settings['PYBPOD_PROTOCOL'] = 'gnagnagna'
434+
# also add an end time
435+
start = datetime.datetime.fromisoformat(self.settings['SESSION_DATETIME'])
436+
self.settings['SESSION_START_TIME'] = rc.ensure_ISO8601(start)
437+
self.settings['SESSION_END_TIME'] = rc.ensure_ISO8601(start + datetime.timedelta(hours=1))
435438
with open(settings_file, 'w') as fid:
436439
json.dump(self.settings, fid)
437440
rc.register_session(self.session_path)
438441
eid = self.one.search(subject=self.subject, date_range=['2018-04-01', '2018-04-01'],
439442
query_type='remote')[0]
440443
ses_info = self.one.alyx.rest('sessions', 'read', id=eid)
441444
self.assertTrue(ses_info['procedures'] == [])
445+
self.assertEqual(self.settings['SESSION_END_TIME'], ses_info['end_time'])
442446
self.one.alyx.rest('sessions', 'delete', id=eid)
443447

444448
def test_register_chained_session(self):
@@ -457,12 +461,13 @@ def test_register_chained_session(self):
457461

458462
# Save experiment description
459463
session_params.write_params(self.session_path, experiment_description)
460-
464+
self.settings['POOP_COUNT'] = 10
461465
with open(behaviour_paths[1].joinpath('_iblrig_taskSettings.raw.json'), 'w') as fid:
462466
json.dump(self.settings, fid)
463467

464468
settings = self.settings.copy()
465469
settings['PYBPOD_PROTOCOL'] = '_iblrig_tasks_passiveChoiceWorld'
470+
settings['POOP_COUNT'] = 53
466471
start_time = (datetime.datetime.fromisoformat(settings['SESSION_DATETIME']) -
467472
datetime.timedelta(hours=1, minutes=2, seconds=12))
468473
settings['SESSION_DATETIME'] = start_time.isoformat()
@@ -475,7 +480,9 @@ def test_register_chained_session(self):
475480
ses_info = self.one.alyx.rest('sessions', 'read', id=session['id'])
476481
self.assertCountEqual(experiment_description['procedures'], ses_info['procedures'])
477482
self.assertCountEqual(experiment_description['projects'], ses_info['projects'])
478-
self.assertCountEqual({'IS_MOCK': False, 'IBLRIG_VERSION': None}, ses_info['json'])
483+
# Poo count should be sum of values in both settings files
484+
expected = {'IS_MOCK': False, 'IBLRIG_VERSION': '5.4.1', 'POOP_COUNT': 63}
485+
self.assertDictEqual(expected, ses_info['json'])
479486
self.assertEqual('2018-04-01T11:46:14.795526', ses_info['start_time'])
480487
# Test task protocol
481488
expected = '_iblrig_tasks_passiveChoiceWorld5.4.1/_iblrig_tasks_ephysChoiceWorld5.4.1'

release_notes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#### 2.32.4
1414
- Add support for variations of the biaseCW task in the json task description
1515

16+
#### 2.32.5
17+
- Minor fixes to IBL registration client, including use of SESSION_END_TIME key
18+
1619
## Release Notes 2.31
1720

1821
### features

0 commit comments

Comments
 (0)