Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/requirements_testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ h5py
igor
klusta
tqdm
nixio>=1.4.3
nixio>=1.5.0b2
axographio>=0.3.1
matplotlib
ipython
Expand Down
2 changes: 1 addition & 1 deletion doc/source/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Neo will still install but the IO module that uses them will fail on loading:
* h5py >= 2.5 for Hdf5IO, KwikIO
* klusta for KwikIO
* igor >= 0.2 for IgorIO
* nixio >= 1.2 for NixIO
* nixio >= 1.5 for NixIO
* stfio for StimfitIO


Expand Down
62 changes: 33 additions & 29 deletions neo/io/nixio.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def __init__(self, filename, mode="rw"):
raise ValueError("Invalid mode specified '{}'. "
"Valid modes: 'ro' (ReadOnly)', 'rw' (ReadWrite),"
" 'ow' (Overwrite).".format(mode))
self.nix_file = nix.File.open(self.filename, filemode, backend="h5py")
self.nix_file = nix.File.open(self.filename, filemode)

if self.nix_file.mode == nix.FileMode.ReadOnly:
self._file_version = '0.5.2'
Expand Down Expand Up @@ -597,18 +597,17 @@ def _write_channelindex(self, chx, nixblock):
)
nixchan.definition = nixsource.definition
chanmd = nixchan.metadata
chanmd["index"] = nix.Value(int(channel))
chanmd["index"] = int(channel)
if len(chx.channel_names):
neochanname = stringify(chx.channel_names[idx])
chanmd["neo_name"] = nix.Value(neochanname)
chanmd["neo_name"] = neochanname
if len(chx.channel_ids):
chanid = chx.channel_ids[idx]
chanmd["channel_id"] = nix.Value(chanid)
chanmd["channel_id"] = chanid
if chx.coordinates is not None:
coords = chx.coordinates[idx]
coordunits = stringify(coords[0].dimensionality)
nixcoords = tuple(nix.Value(c.magnitude.item())
for c in coords)
nixcoords = tuple(c.magnitude.item() for c in coords)
chanprop = chanmd.create_property("coordinates", nixcoords)
chanprop.unit = coordunits

Expand Down Expand Up @@ -1076,26 +1075,28 @@ def _write_property(self, section, name, v):

if isinstance(v, pq.Quantity):
if len(v.shape):
section[name] = list(nix.Value(vv) for vv in v.magnitude)
section.create_property(name, tuple(v.magnitude))
else:
section[name] = nix.Value(v.magnitude.item())
section.create_property(name, v.magnitude.item())
section.props[name].unit = str(v.dimensionality)
elif isinstance(v, datetime):
section[name] = nix.Value(calculate_timestamp(v))
section.create_property(name, calculate_timestamp(v))
elif isinstance(v, string_types):
section[name] = nix.Value(v)
if len(v):
section.create_property(name, v)
else:
section.create_property(name, nix.DataType.String)
elif isinstance(v, bytes):
section[name] = nix.Value(v.decode())
section.create_property(name, v.decode())
elif isinstance(v, Iterable):
values = []
unit = None
definition = None
if len(v) == 0:
# empty list can't be saved in NIX property
# but we can store an empty string and use the
# definition to signify that it should be restored
# as an iterable (list)
values = ""
# NIX supports empty properties but dtype must be specified
# Defaulting to String and using definition to signify empty
# iterable as opposed to empty string
values = nix.DataType.String
definition = EMPTYANNOTATION
elif hasattr(v, "ndim") and v.ndim == 0:
values = v.item()
Expand All @@ -1104,26 +1105,26 @@ def _write_property(self, section, name, v):
else:
for item in v:
if isinstance(item, string_types):
item = nix.Value(item)
item = item
elif isinstance(item, pq.Quantity):
unit = str(item.dimensionality)
item = nix.Value(item.magnitude.item())
item = item.magnitude.item()
elif isinstance(item, Iterable):
self.logger.warn("Multidimensional arrays and nested "
"containers are not currently "
"supported when writing to NIX.")
return None
else:
item = nix.Value(item)
item = item
values.append(item)
section[name] = values
section.create_property(name, values)
section.props[name].unit = unit
if definition:
section.props[name].definition = definition
elif type(v).__module__ == "numpy":
section[name] = nix.Value(v.item())
section.create_property(name, v.item())
else:
section[name] = nix.Value(v)
section.create_property(name, v)
return section.props[name]

@staticmethod
Expand All @@ -1142,17 +1143,20 @@ def _nix_attr_to_neo(nix_obj):
neo_attrs["nix_name"] = nix_obj.name
neo_attrs["description"] = stringify(nix_obj.definition)
if nix_obj.metadata:
for prop in nix_obj.metadata.props:
values = list(v.value for v in prop.values)
for prop in nix_obj.metadata.inherited_properties():
values = prop.values
if prop.unit:
units = prop.unit
values = create_quantity(values, units)
if len(values) == 1:
if not len(values):
if prop.definition == EMPTYANNOTATION:
values = list()
elif prop.data_type == nix.DataType.String:
values = ""
elif len(values) == 1:
values = values[0]
if (not isinstance(values, pq.Quantity) and
values == "" and
prop.definition == EMPTYANNOTATION):
values = list()
else:
values = list(values)
neo_attrs[prop.name] = values
neo_attrs["name"] = stringify(neo_attrs.get("neo_name"))

Expand Down
5 changes: 3 additions & 2 deletions neo/rawio/tests/test_nixrawio.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from neo.rawio.tests.common_rawio_test import BaseTestRawIO


testfname = "neoraw.nix"
testfname = "nixrawio-1.5.nix"

class TestNixRawIO(BaseTestRawIO, unittest.TestCase, ):

class TestNixRawIO(BaseTestRawIO, unittest.TestCase):
rawioclass = NIXRawIO
entities_to_test = [testfname]
files_to_download = [testfname]
Expand Down
33 changes: 13 additions & 20 deletions neo/test/iotest/test_nixio.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,7 @@ def compare_attr(self, neoobj, nixobj):

@classmethod
def create_full_nix_file(cls, filename):
nixfile = nix.File.open(filename, nix.FileMode.Overwrite,
backend="h5py")
nixfile = nix.File.open(filename, nix.FileMode.Overwrite)

nix_block_a = nixfile.create_block(cls.rword(10), "neo.block")
nix_block_a.definition = cls.rsentence(5, 10)
Expand Down Expand Up @@ -422,7 +421,7 @@ def create_full_nix_file(cls, filename):
mtag_st.name, mtag_st.name + ".metadata"
)
mtag_st.metadata = mtag_st_md
mtag_st_md.create_property("t_stop", nix.Value(times[-1] + 1.0))
mtag_st_md.create_property("t_stop", times[-1] + 1.0)

waveforms = cls.rquant((10, 8, 5), 1)
wfname = "{}.waveforms".format(mtag_st.name)
Expand All @@ -439,7 +438,7 @@ def create_full_nix_file(cls, filename):
wfname, "neo.waveforms.metadata"
)
wfda.metadata.create_property("left_sweep",
[nix.Value(20)] * 5)
[20] * 5)
allspiketrains.append(mtag_st)

# Epochs
Expand Down Expand Up @@ -516,9 +515,9 @@ def create_full_nix_file(cls, filename):
nixrc.metadata = nixchx.metadata.create_section(
nixrc.name, "neo.channelindex.metadata"
)
nixrc.metadata.create_property("index", nix.Value(chan))
nixrc.metadata.create_property("channel_id", nix.Value(chan + 1))
dims = tuple(map(nix.Value, cls.rquant(3, 3)))
nixrc.metadata.create_property("index", chan)
nixrc.metadata.create_property("channel_id", chan + 1)
dims = cls.rquant(3, 1)
coordprop = nixrc.metadata.create_property("coordinates", dims)
coordprop.unit = "pm"

Expand Down Expand Up @@ -643,9 +642,7 @@ def setUp(self):
self.filename = os.path.join(self.tempdir, "testnixio.nix")
self.writer = NixIO(self.filename, "ow")
self.io = self.writer
self.reader = nix.File.open(self.filename,
nix.FileMode.ReadOnly,
backend="h5py")
self.reader = nix.File.open(self.filename, nix.FileMode.ReadOnly)

def tearDown(self):
self.writer.close()
Expand Down Expand Up @@ -1209,8 +1206,7 @@ def checksignalcounts(fname):
self.compare_blocks([blk], self.reader.blocks)

# Read back and check counts
scndreader = nix.File.open(secondwrite, mode=nix.FileMode.ReadOnly,
backend="h5py")
scndreader = nix.File.open(secondwrite, mode=nix.FileMode.ReadOnly)
self.compare_blocks([blk], scndreader.blocks)
checksignalcounts(secondwrite)

Expand Down Expand Up @@ -1259,9 +1255,9 @@ def test_to_value(self):
writeprop(section, "val", val)
self.assertEqual(val, section["val"])

# empty string
# empty string (gets stored as empty list)
writeprop(section, "emptystring", "")
self.assertEqual("", section["emptystring"])
self.assertEqual(list(), section["emptystring"])

def test_annotations_special_cases(self):
# Special cases for annotations: empty list, list of strings,
Expand Down Expand Up @@ -1369,22 +1365,19 @@ def test_context_write(self):
with NixIO(self.filename, "ow") as iofile:
iofile.write_block(neoblock)

nixfile = nix.File.open(self.filename, nix.FileMode.ReadOnly,
backend="h5py")
nixfile = nix.File.open(self.filename, nix.FileMode.ReadOnly)
self.compare_blocks([neoblock], nixfile.blocks)
nixfile.close()

neoblock.annotate(**self.rdict(5))
with NixIO(self.filename, "rw") as iofile:
iofile.write_block(neoblock)
nixfile = nix.File.open(self.filename, nix.FileMode.ReadOnly,
backend="h5py")
nixfile = nix.File.open(self.filename, nix.FileMode.ReadOnly)
self.compare_blocks([neoblock], nixfile.blocks)
nixfile.close()

def test_context_read(self):
nixfile = nix.File.open(self.filename, nix.FileMode.Overwrite,
backend="h5py")
nixfile = nix.File.open(self.filename, nix.FileMode.Overwrite)
name_one = self.rword()
name_two = self.rword()
nixfile.create_block(name_one, "neo.block")
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
'igorproio': ['igor'],
'kwikio': ['scipy', 'klusta'],
'neomatlabio': ['scipy>=0.12.0'],
'nixio': ['nixio>=1.4.3'],
'nixio': ['nixio>=1.5.0b2'],
'stimfitio': ['stfio'],
'axographio': ['axographio']
}
Expand Down