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
7 changes: 2 additions & 5 deletions doc/source/images/generate_diagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ def get_rect_height(name, obj):
nlines += len(getattr(obj, '_all_attrs', []))
nlines += len(getattr(obj, '_single_child_objects', []))
nlines += len(getattr(obj, '_multi_child_objects', []))
nlines += len(getattr(obj, '_multi_parent_objects', []))
return nlines * line_heigth


Expand Down Expand Up @@ -100,8 +99,7 @@ def generate_diagram(filename, rect_pos, rect_width, figsize):
for name, pos in rect_pos.items():
htotal = all_h[name]
obj = objs[name]
allrelationship = (list(getattr(obj, '_child_containers', []))
+ list(getattr(obj, '_multi_parent_containers', [])))
allrelationship = list(getattr(obj, '_child_containers', []))

rect = Rectangle(pos, rect_width, htotal,
facecolor='w', edgecolor='k', linewidth=2.)
Expand All @@ -123,8 +121,7 @@ def generate_diagram(filename, rect_pos, rect_width, figsize):
ax.add_patch(rect)

# multi relationship
relationship = (list(getattr(obj, '_multi_child_objects', []))
+ list(getattr(obj, '_multi_parent_containers', [])))
relationship = list(getattr(obj, '_multi_child_objects', []))
pos2 = (pos[1] + htotal - line_heigth * (1.5 + len(relationship))
- rect_height)
rect_height = len(relationship) * line_heigth
Expand Down
4 changes: 2 additions & 2 deletions neo/core/analogsignal.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ class AnalogSignal(BaseSignal):

'''

_single_parent_objects = ('Segment', 'ChannelIndex')
_single_parent_attrs = ('segment', 'channel_index')
_parent_objects = ('Segment', 'ChannelIndex')
_parent_attrs = ('segment', 'channel_index')
_quantity_attr = 'signal'
_necessary_attrs = (('signal', pq.Quantity, 2),
('sampling_rate', pq.Quantity, 0),
Expand Down
93 changes: 22 additions & 71 deletions neo/core/baseneo.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@
Number, Decimal,
np.number, np.bool_)

# handle both Python 2 and Python 3
try:
ALLOWED_ANNOTATION_TYPES += (long, unicode)
except NameError:
pass

logger = logging.getLogger("Neo")


Expand Down Expand Up @@ -179,20 +173,13 @@ class BaseNeo:
and also sets up the :attr:`annotations` dict for additional arguments.

Each class can define one or more of the following class attributes:
:_single_parent_objects: Neo objects that can be parents of this
object. This attribute is used in cases where
only one parent of this class is allowed.
An instance attribute named
class.__name__.lower() will be automatically
defined to hold this parent and will be
initialized to None.
:_multi_parent_objects: Neo objects that can be parents of this
object. This attribute is used in cases where
multiple parents of this class is allowed.
An instance attribute named
class.__name__.lower()+'s' will be
automatically defined to hold this parent and
will be initialized to an empty list.
:_parent_objects: Neo objects that can be parents of this
object. Note that no Neo object can have
more than one parent.
An instance attribute named
class.__name__.lower() will be automatically
defined to hold this parent and will be
initialized to None.
:_necessary_attrs: A list of tuples containing the attributes that the
class must have. The tuple can have 2-4 elements.
The first element is the attribute name.
Expand All @@ -210,15 +197,8 @@ class must have. The tuple can have 2-4 elements.
pretty-printing using iPython.

The following helper properties are available:
:_parent_objects: All parent objects.
:_single_parent_objects: + :_multi_parent_objects:
:_single_parent_containers: The names of the container attributes used
to store :_single_parent_objects:
:_multi_parent_containers: The names of the container attributes used
to store :_multi_parent_objects:
:_parent_containers: All parent container attributes.
:_single_parent_containers: +
:_multi_parent_containers:
:_parent_containers: The names of the container attributes used
to store :_parent_objects:
:parents: All objects that are parents of the current object.
:_all_attrs: All required and optional attributes.
:_necessary_attrs: + :_recommended_attrs:
Expand Down Expand Up @@ -264,11 +244,9 @@ class attributes. :_recommended_attrs: should append
# these attributes control relationships, they need to be
# specified in each child class
# Parent objects whose children can have a single parent
_single_parent_objects = ()
# Attribute names corresponding to _single_parent_objects
_single_parent_attrs = ()
# Parent objects whose children can have multiple parents
_multi_parent_objects = ()
_parent_objects = ()
# Attribute names corresponding to _parent_objects
_parent_attrs = ()

# Attributes that an instance is required to have defined
_necessary_attrs = ()
Expand Down Expand Up @@ -298,10 +276,8 @@ def __init__(self, name=None, description=None, file_origin=None,
self.file_origin = file_origin

# initialize parent containers
for parent in self._single_parent_containers:
for parent in self._parent_containers:
setattr(self, parent, None)
for parent in self._multi_parent_containers:
setattr(self, parent, [])

def annotate(self, **annotations):
"""
Expand Down Expand Up @@ -341,46 +317,21 @@ def _repr_pretty_(self, pp, cycle):
pp.breakable()
self._repr_pretty_attrs_(pp, cycle)

@property
def _single_parent_containers(self):
"""
Containers for parent objects whose children can have a single parent.
"""
return tuple([_reference_name(parent) for parent in
self._single_parent_objects])

@property
def _multi_parent_containers(self):
"""
Containers for parent objects whose children can have multiple parents.
"""
return tuple([_container_name(parent) for parent in
self._multi_parent_objects])

@property
def _parent_objects(self):
"""
All types for parent objects.
"""
return self._single_parent_objects + self._multi_parent_objects

@property
def _parent_containers(self):
"""
All containers for parent objects.
Containers for parent objects.
"""
return self._single_parent_containers + self._multi_parent_containers
return tuple([_reference_name(parent) for parent in
self._parent_objects])

@property
def parents(self):
"""
All parent objects storing the current object.
"""
single = [getattr(self, attr) for attr in
self._single_parent_containers]
multi = [list(getattr(self, attr)) for attr in
self._multi_parent_containers]
return tuple(single + sum(multi, []))
return tuple([getattr(self, attr) for attr in
self._parent_containers])

@property
def _all_attrs(self):
Expand Down Expand Up @@ -420,9 +371,9 @@ def set_parent(self, obj):
Set the appropriate "parent" attribute of this object
according to the type of "obj"
"""
if obj.__class__.__name__ not in self._single_parent_objects:
if obj.__class__.__name__ not in self._parent_objects:
raise TypeError("{} can only have parents of type {}, not {}".format(
self.__class__.__name__, self._single_parent_objects, obj.__class__.__name__))
loc = self._single_parent_objects.index(obj.__class__.__name__)
parent_attr = self._single_parent_attrs[loc]
self.__class__.__name__, self._parent_objects, obj.__class__.__name__))
loc = self._parent_objects.index(obj.__class__.__name__)
parent_attr = self._parent_attrs[loc]
setattr(self, parent_attr, obj)
2 changes: 1 addition & 1 deletion neo/core/channelindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ class ChannelIndex(Container):

_container_child_objects = ('Unit',)
_data_child_objects = ('AnalogSignal', 'IrregularlySampledSignal')
_single_parent_objects = ('Block',)
_parent_objects = ('Block',)
_necessary_attrs = (('index', np.ndarray, 1, np.dtype('i')),)
_recommended_attrs = ((('channel_names', np.ndarray, 1, np.dtype('U')),
('channel_ids', np.ndarray, 1, np.dtype('i')),
Expand Down
2 changes: 1 addition & 1 deletion neo/core/dataobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def __deepcopy__(self, memo):
# thus creating a lot of overhead
# But keeping the reference to the same parent is not desired either, because this would be unidirectional
# When deepcopying top-down, e.g. a whole block, the links will be handled by the parent
if k in self._single_parent_attrs:
if k in self._parent_attrs:
setattr(new_obj, k, None)
continue
try:
Expand Down
4 changes: 2 additions & 2 deletions neo/core/epoch.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ class Epoch(DataObject):

'''

_single_parent_objects = ('Segment',)
_single_parent_attrs = ('segment',)
_parent_objects = ('Segment',)
_parent_attrs = ('segment',)
_quantity_attr = 'times'
_necessary_attrs = (('times', pq.Quantity, 1), ('durations', pq.Quantity, 1),
('labels', np.ndarray, 1, np.dtype('U')))
Expand Down
4 changes: 2 additions & 2 deletions neo/core/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ class Event(DataObject):

'''

_single_parent_objects = ('Segment',)
_single_parent_attrs = ('segment',)
_parent_objects = ('Segment',)
_parent_attrs = ('segment',)
_quantity_attr = 'times'
_necessary_attrs = (('times', pq.Quantity, 1), ('labels', np.ndarray, 1, np.dtype('U')))

Expand Down
2 changes: 1 addition & 1 deletion neo/core/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Group(Container):
'Event', 'Epoch', 'ChannelView', 'ImageSequence'
)
_container_child_objects = ('Segment', 'Group')
_single_parent_objects = ('Block',)
_parent_objects = ('Block',)

def __init__(self, objects=None, name=None, description=None, file_origin=None,
allowed_types=None, **annotations):
Expand Down
4 changes: 2 additions & 2 deletions neo/core/imagesequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ class ImageSequence(BaseSignal):
(:attr:`t_start` + :attr:`duration`)
"""

_single_parent_objects = ("Segment",)
_single_parent_attrs = ("segment",)
_parent_objects = ("Segment",)
_parent_attrs = ("segment",)
_quantity_attr = "image_data"
_necessary_attrs = (
("image_data", pq.Quantity, 3),
Expand Down
4 changes: 2 additions & 2 deletions neo/core/irregularlysampledsignal.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ class IrregularlySampledSignal(BaseSignal):

'''

_single_parent_objects = ('Segment', 'ChannelIndex')
_single_parent_attrs = ('segment', 'channel_index')
_parent_objects = ('Segment', 'ChannelIndex')
_parent_attrs = ('segment', 'channel_index')
_quantity_attr = 'signal'
_necessary_attrs = (('times', pq.Quantity, 1), ('signal', pq.Quantity, 2))

Expand Down
2 changes: 1 addition & 1 deletion neo/core/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class Segment(Container):
_data_child_objects = ('AnalogSignal',
'Epoch', 'Event',
'IrregularlySampledSignal', 'SpikeTrain', 'ImageSequence')
_single_parent_objects = ('Block',)
_parent_objects = ('Block',)
_recommended_attrs = ((('file_datetime', datetime),
('rec_datetime', datetime),
('index', int)) +
Expand Down
4 changes: 2 additions & 2 deletions neo/core/spiketrain.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,8 @@ class SpikeTrain(DataObject):

'''

_single_parent_objects = ('Segment', 'Unit')
_single_parent_attrs = ('segment', 'unit')
_parent_objects = ('Segment', 'Unit')
_parent_attrs = ('segment', 'unit')
_quantity_attr = 'times'
_necessary_attrs = (('times', pq.Quantity, 1), ('t_start', pq.Quantity, 0),
('t_stop', pq.Quantity, 0))
Expand Down
2 changes: 1 addition & 1 deletion neo/core/unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class Unit(Container):
'''

_data_child_objects = ('SpikeTrain',)
_single_parent_objects = ('ChannelIndex',)
_parent_objects = ('ChannelIndex',)
_recommended_attrs = Container._recommended_attrs

def __init__(self, name=None, description=None, file_origin=None,
Expand Down
4 changes: 2 additions & 2 deletions neo/core/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ class ChannelView(BaseNeo):
Note: Any other additional arguments are assumed to be user-specific
metadata and stored in :attr:`annotations`.
"""
_single_parent_objects = ('Segment',)
_single_parent_attrs = ('segment',)
_parent_objects = ('Segment',)
_parent_attrs = ('segment',)
_necessary_attrs = (
('index', np.ndarray, 1, np.dtype('i')),
('obj', ('AnalogSignal', 'IrregularlySampledSignal'), 1)
Expand Down
6 changes: 3 additions & 3 deletions neo/io/proxyobjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class AnalogSignalProxy(BaseProxy):
>>> some_channel_of_anasig = proxy_anasig.load(channel_indexes=[0,5,10])

'''
_single_parent_objects = ('Segment', 'ChannelIndex')
_parent_objects = ('Segment', 'ChannelIndex')
_necessary_attrs = (('sampling_rate', pq.Quantity, 0),
('t_start', pq.Quantity, 0))
_recommended_attrs = BaseNeo._recommended_attrs
Expand Down Expand Up @@ -287,7 +287,7 @@ class SpikeTrainProxy(BaseProxy):

'''

_single_parent_objects = ('Segment', 'Unit')
_parent_objects = ('Segment', 'Unit')
_quantity_attr = 'times'
_necessary_attrs = (('t_start', pq.Quantity, 0),
('t_stop', pq.Quantity, 0))
Expand Down Expand Up @@ -385,7 +385,7 @@ def load(self, time_slice=None, strict_slicing=True,


class _EventOrEpoch(BaseProxy):
_single_parent_objects = ('Segment',)
_parent_objects = ('Segment',)
_quantity_attr = 'times'

def __init__(self, rawio=None, event_channel_index=None, block_index=0, seg_index=0):
Expand Down
6 changes: 2 additions & 4 deletions neo/test/coretest/test_analogsignal.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,9 @@ def test__children(self):
chx.analogsignals = [signal]
chx.create_many_to_one_relationship()

self.assertEqual(signal._single_parent_objects, ('Segment', 'ChannelIndex'))
self.assertEqual(signal._multi_parent_objects, ())
self.assertEqual(signal._parent_objects, ('Segment', 'ChannelIndex'))

self.assertEqual(signal._single_parent_containers, ('segment', 'channel_index'))
self.assertEqual(signal._multi_parent_containers, ())
self.assertEqual(signal._parent_containers, ('segment', 'channel_index'))

self.assertEqual(signal._parent_objects, ('Segment', 'ChannelIndex'))
self.assertEqual(signal._parent_containers, ('segment', 'channel_index'))
Expand Down
6 changes: 2 additions & 4 deletions neo/test/coretest/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,9 @@ def test_annotate(self):
def test__children(self):
base = BaseNeo()

self.assertEqual(base._single_parent_objects, ())
self.assertEqual(base._multi_parent_objects, ())
self.assertEqual(base._parent_objects, ())

self.assertEqual(base._single_parent_containers, ())
self.assertEqual(base._multi_parent_containers, ())
self.assertEqual(base._parent_containers, ())

self.assertEqual(base._parent_objects, ())
self.assertEqual(base._parent_containers, ())
Expand Down
6 changes: 2 additions & 4 deletions neo/test/coretest/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,8 @@ def test__children(self):
self.assertEqual(self.blk1._container_child_objects,
('Segment', 'ChannelIndex', 'Group'))
self.assertEqual(self.blk1._data_child_objects, ())
self.assertEqual(self.blk1._single_parent_objects, ())
self.assertEqual(self.blk1._parent_objects, ())
self.assertEqual(self.blk1._multi_child_objects, ())
self.assertEqual(self.blk1._multi_parent_objects, ())
self.assertEqual(self.blk1._child_properties,
('Unit',))

Expand All @@ -272,9 +271,8 @@ def test__children(self):
self.assertEqual(self.blk1._data_child_containers, ())
self.assertEqual(self.blk1._single_child_containers,
('segments', 'channel_indexes', 'groups'))
self.assertEqual(self.blk1._single_parent_containers, ())
self.assertEqual(self.blk1._parent_containers, ())
self.assertEqual(self.blk1._multi_child_containers, ())
self.assertEqual(self.blk1._multi_parent_containers, ())

self.assertEqual(self.blk1._child_objects,
('Segment', 'ChannelIndex', 'Group'))
Expand Down
Loading