Skip to content

Commit 4592905

Browse files
committed
fix: started cleaning up classes - removing prints and adding tests
1 parent dffd0fb commit 4592905

File tree

5 files changed

+107
-77
lines changed

5 files changed

+107
-77
lines changed

nibabel/cifti/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from .parse_cifti_fast import create_cifti_image
2121
from .cifti import (CiftiMetaData, CiftiHeader, CiftiImage, CiftiLabel,
22-
CiftiLabelTable, CiftiNVPair, CiftiVertexIndices,
22+
CiftiLabelTable, CiftiVertexIndices,
2323
CiftiVoxelIndicesIJK, CiftiBrainModel, CiftiMatrix,
2424
CiftiMatrixIndicesMap, CiftiNamedMap, CiftiParcel,
2525
CiftiSurface, CiftiTransformationMatrixVoxelIndicesIJKtoXYZ,

nibabel/cifti/cifti.py

Lines changed: 64 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import numpy as np
2323

2424
DEBUG_PRINT = False
25+
2526
CIFTI_MAP_TYPES = ('CIFTI_INDEX_TYPE_BRAIN_MODELS',
2627
'CIFTI_INDEX_TYPE_PARCELS',
2728
'CIFTI_INDEX_TYPE_SERIES',
@@ -71,58 +72,77 @@
7172

7273

7374
class CiftiMetaData(object):
74-
""" A list of GiftiNVPairs in stored in
75-
the list self.data """
76-
def __init__(self, nvpair = None):
75+
""" A list of CiftiNVPairs in stored in the list self.data """
76+
77+
def __init__(self, nvpair=None):
7778
self.data = []
78-
if not nvpair is None:
79-
if isinstance(nvpair, list):
80-
self.data.extend(nvpair)
79+
self.add_metadata(nvpair)
80+
81+
def _add_remove_metadata(self, metadata, func):
82+
pairs = []
83+
if isinstance(metadata, (list, tuple)):
84+
if isinstance(metadata[0], basestring):
85+
if len(metadata) != 2:
86+
raise ValueError('nvpair must be a 2-list or 2-tuple')
87+
pairs = [tuple((metadata[0], metadata[1]))]
88+
else:
89+
for item in metadata:
90+
self._add_remove_metadata(item, func)
91+
return
92+
elif isinstance(metadata, dict):
93+
pairs = metadata.items()
94+
else:
95+
raise ValueError('nvpair input must be a list, tuple or dict')
96+
for pair in pairs:
97+
if func == 'add':
98+
if pair not in self.data:
99+
self.data.append(pair)
100+
elif func == 'remove':
101+
self.data.remove(pair)
81102
else:
82-
self.data.append(nvpair)
103+
raise ValueError('Unknown func %s' % func)
83104

84-
@classmethod
85-
def from_dict(klass, data_dict):
86-
meda = klass()
87-
for k,v in data_dict.items():
88-
nv = CiftiNVPair(k, v)
89-
meda.data.append(nv)
90-
return meda
105+
def add_metadata(self, metadata):
106+
"""Add metadata key-value pairs
91107
92-
def get_metadata(self):
93-
""" Returns metadata as dictionary """
94-
self.data_as_dict = {}
95-
for ele in self.data:
96-
self.data_as_dict[ele.name] = ele.value
97-
return self.data_as_dict
108+
This allows storing multiple keys with the same name but different
109+
values.
110+
111+
112+
Parameters
113+
----------
114+
metadata : 2-List, 2-Tuple, Dictionary, List[2-List or 2-Tuple]
115+
Tuple[2-List or 2-Tuple]
116+
117+
Returns
118+
-------
119+
None
120+
121+
"""
122+
if metadata is None:
123+
return
124+
self._add_remove_metadata(metadata, 'add')
125+
126+
def remove_metadata(self, metadata):
127+
if metadata is None:
128+
return
129+
self._add_remove_metadata(metadata, 'remove')
98130

99131
def to_xml(self, prefix='', indent=' '):
100132
if len(self.data) == 0:
101133
return ''
102134
res = "%s<MetaData>\n" % prefix
103135
preindent = prefix + indent
104-
for ele in self.data:
136+
for name, value in self.data:
105137
nvpair = """%s<MD>
106138
%s<Name>%s</Name>
107139
%s<Value>%s</Value>
108-
%s</MD>\n""" % (preindent, preindent + indent, ele.name, preindent + indent,
109-
ele.value, preindent)
140+
%s</MD>\n""" % (preindent, preindent + indent, name, preindent + indent,
141+
value, preindent)
110142
res += nvpair
111143
res += "%s</MetaData>\n" % prefix
112144
return res
113145

114-
def print_summary(self):
115-
print(self.get_metadata())
116-
117-
118-
class CiftiNVPair(object):
119-
120-
name = str
121-
value = str
122-
123-
def __init__(self, name = '', value = ''):
124-
self.name = name
125-
self.value = value
126146

127147
class CiftiLabelTable(object):
128148

@@ -160,16 +180,6 @@ def print_summary(self):
160180

161181

162182
class CiftiLabel(object):
163-
key = int
164-
label = str
165-
# rgba
166-
# freesurfer examples seem not to conform
167-
# to datatype "NIFTI_TYPE_RGBA32" because they
168-
# are floats, not unsigned 32-bit integers
169-
red = float
170-
green = float
171-
blue = float
172-
alpha = float
173183

174184
def __init__(self, key = 0, label = '', red = None,\
175185
green = None, blue = None, alpha = None):
@@ -337,7 +347,7 @@ def add_cifti_vertices(self, vertices):
337347
self.vertices.append(vertices)
338348
self.numVA += 1
339349
else:
340-
print("mim paramater must be of type CiftiMatrixIndicesMap")
350+
raise TypeError("Not a valid CiftiVertices instance")
341351

342352
def remove_cifti_vertices(self, ith):
343353
""" Removes the ith vertices element from the CiftiParcel """
@@ -543,7 +553,7 @@ def add_cifti_brain_model(self, brain_model):
543553
self.brainModels.append(brain_model)
544554
self.numBrainModels += 1
545555
else:
546-
print("brain_model parameter must be of type CiftiBrainModel")
556+
raise TypeError("Not a valid CiftiBrainModel instance")
547557

548558
def remove_cifti_brain_model(self, ith):
549559
""" Removes the ith brain model element from the CiftiMatrixIndicesMap """
@@ -561,7 +571,7 @@ def add_cifti_named_map(self, named_map):
561571
self.namedMaps.append(named_map)
562572
self.numNamedMaps += 1
563573
else:
564-
print("named_map parameter must be of type CiftiNamedMap")
574+
raise TypeError("Not a valid CiftiNamedMap instance")
565575

566576
def remove_cifti_named_map(self, ith):
567577
""" Removes the ith named_map element from the CiftiMatrixIndicesMap """
@@ -579,7 +589,7 @@ def add_cifti_parcel(self, parcel):
579589
self.parcels.append(parcel)
580590
self.numParcels += 1
581591
else:
582-
print("parcel parameter must be of type CiftiParcel")
592+
raise TypeError("Not a valid CiftiParcel instance")
583593

584594
def remove_cifti_parcel(self, ith):
585595
""" Removes the ith parcel element from the CiftiMatrixIndicesMap """
@@ -597,7 +607,7 @@ def add_cifti_surface(self, surface):
597607
self.surfaces.append(surface)
598608
self.numSurfaces += 1
599609
else:
600-
print("surface parameter must be of type CiftiSurface")
610+
raise TypeError("Not a valid CiftiSurface instance")
601611

602612
def remove_cifti_surface(self, ith):
603613
""" Removes the ith surface element from the CiftiMatrixIndicesMap """
@@ -614,7 +624,7 @@ def set_cifti_volume(self, volume):
614624
if isinstance(volume, CiftiVolume):
615625
self.volume = volume
616626
else:
617-
print("volume parameter must be of type CiftiVolume")
627+
raise TypeError("Not a valid CiftiVolume instance")
618628

619629
def remove_cifti_volume(self):
620630
""" Removes the volume element from the CiftiMatrixIndicesMap """
@@ -691,7 +701,7 @@ def add_cifti_matrix_indices_map(self, mim):
691701
self.mims.append(mim)
692702
self.numMIM += 1
693703
else:
694-
print("mim paramater must be of type CiftiMatrixIndicesMap")
704+
raise TypeError("Not a valid CiftiMatrixIndicesMap instance")
695705

696706
def remove_cifti_matrix_indices_map(self, ith):
697707
""" Removes the ith matrix indices map element from the CiftiMatrix """
@@ -788,7 +798,7 @@ def to_filename(self, filename):
788798
if not filename.endswith('nii'):
789799
ValueError('CIFTI files have to be stored as uncompressed NIFTI2')
790800
from ..nifti2 import Nifti2Image
791-
from ..nifti1 import Nifti1Extensions, Nifti1Extension
801+
from ..nifti1 import Nifti1Extension
792802
data = np.reshape(self.data, [1, 1, 1, 1] + list(self.data.shape))
793803
header = self.extra
794804
extension = Nifti1Extension(32, self.header.to_xml())
@@ -837,7 +847,7 @@ def load(filename):
837847
IOError : if `filename` does not exist
838848
"""
839849
from ..nifti2 import load as Nifti2load
840-
return Nifti2load(filename)
850+
return Nifti2load(filename).as_cifti()
841851

842852

843853
def save(img, filename):

nibabel/cifti/parse_cifti_fast.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import numpy as np
1717

1818
from .cifti import (CiftiMetaData, CiftiImage, CiftiHeader, CiftiLabel,
19-
CiftiLabelTable, CiftiNVPair, CiftiVertexIndices,
19+
CiftiLabelTable, CiftiVertexIndices,
2020
CiftiVoxelIndicesIJK, CiftiBrainModel, CiftiMatrix,
2121
CiftiMatrixIndicesMap, CiftiNamedMap, CiftiParcel,
2222
CiftiSurface, CiftiTransformationMatrixVoxelIndicesIJKtoXYZ,
@@ -66,7 +66,7 @@ def StartElementHandler(self, name, attrs):
6666
assert isinstance(parent, (CiftiMatrix, CiftiNamedMap))
6767
self.struct_state.append(meta)
6868
elif name == 'MD':
69-
pair = CiftiNVPair()
69+
pair = ['', '']
7070
self.fsm_state.append('MD')
7171
self.struct_state.append(pair)
7272
elif name == 'Name':
@@ -223,7 +223,7 @@ def EndElementHandler(self, name):
223223
self.fsm_state.pop()
224224
pair = self.struct_state.pop()
225225
meta = self.struct_state[-1]
226-
if pair.name is not None:
226+
if pair[0]:
227227
meta.data.append(pair)
228228
elif name == 'Name':
229229
self.write_to = None
@@ -299,13 +299,11 @@ def flush_chardata(self):
299299
if self.write_to == 'Name':
300300
data = data.strip()
301301
pair = self.struct_state[-1]
302-
assert isinstance(pair, CiftiNVPair)
303-
pair.name = data
302+
pair[0] = data
304303
elif self.write_to == 'Value':
305304
data = data.strip()
306305
pair = self.struct_state[-1]
307-
assert isinstance(pair, CiftiNVPair)
308-
pair.value = data
306+
pair[1] = data
309307
elif self.write_to == 'Vertices':
310308
# conversion to numpy array
311309
c = StringIO(data.strip().decode('utf-8'))
@@ -320,13 +318,13 @@ def flush_chardata(self):
320318
c.close()
321319
elif self.write_to == 'VertexIndices':
322320
# conversion to numpy array
323-
c = StringIO(data.strip().decode('utf-8'))
321+
c = StringIO(data.strip())
324322
index = self.struct_state[-1]
325323
index.indices = np.genfromtxt(c, dtype=np.int)
326324
c.close()
327325
elif self.write_to == 'TransformMatrix':
328326
# conversion to numpy array
329-
c = StringIO(data.strip().decode('utf-8'))
327+
c = StringIO(data.strip())
330328
transform = self.struct_state[-1]
331329
transform.matrix = np.genfromtxt(c, dtype=np.float)
332330
c.close()

nibabel/cifti/tests/test_cifti.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
""" Testing gifti objects
2+
"""
3+
4+
import numpy as np
5+
6+
from ...nifti1 import data_type_codes, intent_codes
7+
8+
from ... import cifti as ci
9+
10+
from numpy.testing import (assert_array_almost_equal,
11+
assert_array_equal)
12+
13+
from nose.tools import assert_true, assert_equal, assert_raises
14+
15+
16+
def test_cifti_metadata():
17+
md = ci.CiftiMetaData()
18+
assert_equal(md.data, [])
19+
assert_raises(ValueError, md.add_metadata, ['a'])
20+
md.add_metadata([('a', 'aval'), ('b', 'bval')])
21+
assert_true(len(md.data) == 2)
22+
md.add_metadata([['a', 'aval'], ['b', 'bval']])
23+
assert_true(len(md.data) == 2)
24+
md.add_metadata({'a': 'aval', 'b': 'bval'})
25+
assert_true(len(md.data) == 2)
26+
md.add_metadata({'a': 'aval', 'd': 'dval'})
27+
assert_true(len(md.data) == 3)
28+
md.remove_metadata({'a': 'aval', 'd': 'dval'})
29+
assert_true(len(md.data) == 1)
30+
assert_raises(ValueError, md.remove_metadata, {'a': 'aval', 'd': 'dval'})
31+
assert_equal(md.to_xml(),
32+
'<MetaData>\n <MD>\n <Name>b</Name>\n <Value>bval</Value>\n </MD>\n</MetaData>\n')
33+
md.remove_metadata(['b', 'bval'])
34+
assert_true(len(md.data) == 0)
35+
assert_true(md.to_xml() == '')

nibabel/cifti/tests/test_ciftiio.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,3 @@ def test_readwritedata():
8181
assert_array_almost_equal(img.data,
8282
img2.data)
8383

84-
85-
def test_newmetadata():
86-
img = ci.CiftiImage()
87-
attr = ci.CiftiNVPair(name = 'mykey', value = 'val1')
88-
newmeta = ci.CiftiMetaData(attr)
89-
img.header.matrix.meta = newmeta
90-
myme = img.header.matrix.meta.get_metadata()
91-
assert_true('mykey' in myme)
92-
newmeta = ci.CiftiMetaData.from_dict( {'mykey1' : 'val2'} )
93-
img.header.matrix.meta = newmeta
94-
myme = img.header.matrix.meta.get_metadata()
95-
assert_true('mykey1' in myme)
96-
assert_false('mykey' in myme)

0 commit comments

Comments
 (0)