Skip to content

Commit 68c69df

Browse files
authored
Develop (#719)
* Fix loading of personal projects extractor map * flake8 * Fix unrelated test
1 parent b52d04d commit 68c69df

File tree

7 files changed

+88
-13
lines changed

7 files changed

+88
-13
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.28.1'
5+
__version__ = '2.28.2'
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/extractors/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ def _get_task_extractor_map():
395395
# look if there are custom extractor types in the personal projects repo
396396
import projects.base
397397
custom_extractors = Path(projects.base.__file__).parent.joinpath(FILENAME)
398-
with open(custom_extractors) as fp:
398+
with open(custom_extractors, 'r') as fp:
399399
custom_task_types = json.load(fp)
400400
task_extractors.update(custom_task_types)
401401
except (ModuleNotFoundError, FileNotFoundError):

ibllib/io/raw_data_loaders.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
# @Author: Niccolò Bonacchi, Miles Wells
44
# @Date: Monday, July 16th 2018, 1:28:46 pm
55
"""
6-
Raw Data Loader functions for PyBpod rig
6+
Raw Data Loader functions for PyBpod rig.
77
8-
Module contains one loader function per raw datafile
8+
Module contains one loader function per raw datafile.
99
"""
1010
import re
1111
import json
@@ -107,7 +107,7 @@ def load_data(session_path: Union[str, Path], task_collection='raw_behavior_data
107107

108108

109109
def load_camera_frameData(session_path, camera: str = 'left', raw: bool = False) -> pd.DataFrame:
110-
""" Loads binary frame data from Bonsai camera recording workflow.
110+
"""Loads binary frame data from Bonsai camera recording workflow.
111111
112112
Args:
113113
session_path (StrPath): Path to session folder

ibllib/plots/snapshot.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def register_image(self, image_file, text='', json_field=None, width=None):
216216
"""
217217
# the protocol is not compatible with byte streaming and json, so serialize the json object here
218218
# Make sure that user is logged in, if not, try to log in
219-
assert self.one.alyx.is_logged_in, "No Alyx user is logged in, try running one.alyx.authenticate() first"
219+
assert self.one.alyx.is_logged_in, 'No Alyx user is logged in, try running one.alyx.authenticate() first'
220220
note = {
221221
'user': self.one.alyx.user, 'content_type': self.content_type, 'object_id': self.object_id,
222222
'text': text, 'width': width, 'json': json.dumps(json_field)}
@@ -232,16 +232,15 @@ def register_image(self, image_file, text='', json_field=None, width=None):
232232
# Catch error that results from object_id - content_type mismatch
233233
try:
234234
note_db = self.one.alyx.rest('notes', 'create', data=note, files={'image': fig_open})
235-
fig_open.close()
236235
return note_db
237236
except requests.HTTPError as e:
238-
if "matching query does not exist.'" in str(e):
239-
fig_open.close()
237+
if 'matching query does not exist' in str(e):
240238
_logger.error(f'The object_id {self.object_id} does not match an object of type {self.content_type}')
241239
_logger.debug(traceback.format_exc())
242240
else:
243-
fig_open.close()
244-
raise
241+
raise e
242+
finally:
243+
fig_open.close()
245244

246245
def register_images(self, image_list=None, texts=None, widths=None, jsons=None):
247246
"""
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import json
2+
import unittest
3+
import tempfile
4+
from pathlib import Path
5+
from unittest.mock import patch, MagicMock
6+
7+
from ibllib.io.extractors import base
8+
9+
10+
class TestExtractorMaps(unittest.TestCase):
11+
"""Tests for functions that return Bpod extractor classes."""
12+
def setUp(self):
13+
# Store original __import__
14+
self.orig_import = __import__
15+
tmp = tempfile.TemporaryDirectory()
16+
self.addCleanup(tmp.cleanup)
17+
self.custom_extractors_path = Path(tmp.name).joinpath('task_extractor_map.json')
18+
self.custom_extractors = {'fooChoiceWorld': 'Bar'}
19+
self.projects = MagicMock()
20+
self.projects.base.__file__ = str(self.custom_extractors_path.with_name('__init__.py'))
21+
with open(self.custom_extractors_path, 'w') as fp:
22+
json.dump(self.custom_extractors, fp)
23+
24+
def import_mock(self, name, *args):
25+
"""Return mock for project_extraction imports."""
26+
if name == 'projects' or name == 'projects.base':
27+
return self.projects
28+
return self.orig_import(name, *args)
29+
30+
def test_get_task_extractor_map(self):
31+
"""Test ibllib.io.extractors.base._get_task_extractor_map function."""
32+
# Check the custom map is loaded
33+
with patch('builtins.__import__', side_effect=self.import_mock):
34+
extractors = base._get_task_extractor_map()
35+
self.assertTrue(self.custom_extractors.items() < extractors.items())
36+
# Test handles case where module not installed
37+
with patch('builtins.__import__', side_effect=ModuleNotFoundError):
38+
extractors = base._get_task_extractor_map()
39+
self.assertFalse(set(self.custom_extractors.items()).issubset(set(extractors.items())))
40+
# Remove the file and check exception is caught
41+
self.custom_extractors_path.unlink()
42+
extractors = base._get_task_extractor_map()
43+
self.assertFalse(set(self.custom_extractors.items()).issubset(set(extractors.items())))
44+
45+
def test_get_bpod_extractor_class(self):
46+
"""Test ibllib.io.extractors.base.get_bpod_extractor_class function."""
47+
# installe
48+
# alf_path = self.custom_extractors_path.parent.joinpath('subject', '2020-01-01', '001', 'raw_task_data_00')
49+
# alf_path.mkdir(parents=True)
50+
settings_file = Path(__file__).parent.joinpath(
51+
'data', 'session_biased_ge5', 'raw_behavior_data', '_iblrig_taskSettings.raw.json'
52+
)
53+
# shutil.copy(settings_file, alf_path)
54+
session_path = settings_file.parents[1]
55+
self.assertEqual('BiasedTrials', base.get_bpod_extractor_class(session_path))
56+
session_path = str(session_path).replace('session_biased_ge5', 'session_training_ge5')
57+
self.assertEqual('TrainingTrials', base.get_bpod_extractor_class(session_path))
58+
session_path = str(session_path).replace('session_training_ge5', 'foobar')
59+
self.assertRaises(ValueError, base.get_bpod_extractor_class, session_path)
60+
61+
def test_protocol2extractor(self):
62+
"""Test ibllib.io.extractors.base.protocol2extractor function."""
63+
# Test fuzzy match
64+
(proc, expected), = self.custom_extractors.items()
65+
with patch('builtins.__import__', side_effect=self.import_mock):
66+
extractor = base.protocol2extractor('_mw_' + proc)
67+
self.assertEqual(expected, extractor)
68+
# Test unknown protocol
69+
self.assertRaises(ValueError, base.protocol2extractor, proc)
70+
71+
72+
if __name__ == '__main__':
73+
unittest.main()

ibllib/tests/test_plots.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class TestSnapshot(unittest.TestCase):
2222

2323
@classmethod
2424
def setUpClass(cls):
25-
# Make a small image an store in tmp file
25+
# Make a small image and store in tmp file
2626
cls.tmp_dir = tempfile.TemporaryDirectory()
2727
cls.img_file = Path(cls.tmp_dir.name).joinpath('test.png')
2828
image = Image.new('RGBA', size=(WIDTH, HEIGHT), color=(155, 0, 0))
@@ -40,7 +40,7 @@ def setUpClass(cls):
4040
cls.eid = str(eid)
4141

4242
def _get_image(self, url):
43-
# This is a bit of a hack because when running a the server locally, the request to the media folder fail
43+
# This is a bit of a hack because when running the server locally, the request to the media folder fails
4444
rel_path = urlparse(url).path[1:]
4545
try:
4646
img_file = list(Path('/var/www/').rglob(rel_path))[0]

release_notes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
- Typo in ibllib.pipes.video_tasks.EphysPostDLC class
1414
- ibllib.io.raw_data_loaders.patch_settings works with iblrigv8 settings files
1515

16+
#### 2.28.2
17+
- Fix loading of personal projects extractor map
18+
1619
## Release Notes 2.27
1720

1821
### features

0 commit comments

Comments
 (0)