Skip to content

Commit 08c1029

Browse files
authored
Merge pull request #34 from int-brain-lab/jsonable
load jsonable from iblrig available to all installs
2 parents 3f3d7c8 + 4b31571 commit 08c1029

File tree

12 files changed

+88
-2
lines changed

12 files changed

+88
-2
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
* Minor releases (X.1.X) are new features such as added functions or small changes that don't cause major compatibility issues.
44
* Major releases (1.X.X) are major new features or changes that break backward compatibility in a big way.
55

6+
## [Latest](https://github.com/int-brain-lab/iblutil/commits/main) [1.14.0]
7+
8+
### Added
9+
10+
- io.jsonable.load_task_jsonable: read and format iblrig raw data to a trials table Dataframe and a list of raw Bpod trials
11+
- util.Listable: returns a typing class that is the union of input class and a sequence thereof
12+
613
## [Latest](https://github.com/int-brain-lab/iblutil/commits/main) [1.13.0]
714

815
### Added

MANIFEST.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
recursive-include tests/fixtures *

iblutil/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.13.0'
1+
__version__ = '1.14.0'

iblutil/io/jsonable.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import json
2+
from typing import Any, List, Tuple
3+
4+
import pandas as pd
25

36

47
def read(file):
@@ -21,3 +24,37 @@ def write(file, data):
2124

2225
def append(file, data):
2326
_write(file, data, 'a')
27+
28+
29+
def load_task_jsonable(jsonable_file, offset: int = None) -> Tuple[pd.DataFrame, List[Any]]:
30+
"""
31+
Reads in a task data jsonable file and returns a trials dataframe and a bpod data list.
32+
33+
Parameters
34+
----------
35+
jsonable_file : str, pathlib.Path
36+
Full path to jsonable file.
37+
offset : int
38+
The offset to start reading from (default: None).
39+
40+
Returns
41+
-------
42+
pandas.DataFrame
43+
A DataFrame with the trial info in the same format as the Session trials table.
44+
list
45+
Timing data for each trial.
46+
"""
47+
trials_table = []
48+
with open(jsonable_file) as f:
49+
if offset is not None:
50+
f.seek(offset, 0)
51+
for line in f:
52+
trials_table.append(json.loads(line))
53+
54+
# pop-out the bpod data from the table
55+
bpod_data = []
56+
for td in trials_table:
57+
bpod_data.append(td.pop('behavior_data'))
58+
59+
trials_table = pd.DataFrame(trials_table)
60+
return trials_table, bpod_data
File renamed without changes.

iblutil/tests/fixtures/task_data_short.jsonable

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

tests/test_io.py renamed to iblutil/tests/test_io.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,5 +220,27 @@ def tearDown(self) -> None:
220220
os.unlink(self.tfile.name)
221221

222222

223+
class TestLoadTaskData(unittest.TestCase):
224+
def test_load_task_jsonable(self):
225+
jsonable_file = Path(__file__).parent.joinpath('fixtures', 'task_data_short.jsonable')
226+
trials_table, bpod_data = jsonable.load_task_jsonable(jsonable_file)
227+
assert trials_table.shape[0] == 2
228+
assert len(bpod_data) == 2
229+
230+
def test_load_task_jsonable_partial(self):
231+
jsonable_file = Path(__file__).parent.joinpath('fixtures', 'task_data_short.jsonable')
232+
with open(jsonable_file) as fp:
233+
fp.readline()
234+
offset = fp.tell()
235+
trials_table, bpod_data = jsonable.load_task_jsonable(jsonable_file, offset=offset)
236+
237+
trials_table_full, bpod_data_full = jsonable.load_task_jsonable(jsonable_file)
238+
for c in trials_table.columns:
239+
if not np.isnan(trials_table[c][0]):
240+
np.testing.assert_equal(trials_table_full[c].values[-1], trials_table[c][0])
241+
242+
assert bpod_data_full[-1] == bpod_data[0]
243+
244+
223245
if __name__ == '__main__':
224246
unittest.main(exit=False, verbosity=2)
File renamed without changes.
File renamed without changes.
File renamed without changes.

tests/test_util.py renamed to iblutil/tests/test_util.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import unittest
22
import types
3+
import typing
34
from pathlib import Path
45
import tempfile
56
import logging
@@ -230,5 +231,16 @@ def test_ensure_list(self):
230231
self.assertEqual([x], util.ensure_list(x, exclude_type=(np.ndarray)))
231232

232233

234+
class TestListable(unittest.TestCase):
235+
"""Test Listable typing class."""
236+
237+
def test_listable(self):
238+
"""Test listable type from given class."""
239+
listable = util.Listable(str)
240+
self.assertIs(listable, typing.Union[str, typing.Sequence[str]])
241+
listable = util.Listable(dict)
242+
self.assertIs(listable, typing.Union[dict, typing.Sequence[dict]])
243+
244+
233245
if __name__ == '__main__':
234246
unittest.main(exit=False)

iblutil/util.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import copy
88
import logging
99
import sys
10-
from typing import Union, Iterable
10+
from typing import Union, Iterable, Sequence
1111

1212
import numpy as np
1313

@@ -23,6 +23,11 @@
2323
'CRITICAL': 'bold_purple'}
2424

2525

26+
def Listable(t):
27+
"""Return a typing.Union if the input and sequence of input."""
28+
return Union[t, Sequence[t]]
29+
30+
2631
class Bunch(dict):
2732
"""A subclass of dictionary with an additional dot syntax."""
2833

0 commit comments

Comments
 (0)