Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

recurse on Proxy objects #575

Merged
merged 10 commits into from
Jul 31, 2018
33 changes: 27 additions & 6 deletions src/pynwb/form/build/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@


class Proxy(object):
"""
A temporary object to represent a Container. This gets used when resolving the true location of a
Container's parent.

Proxy objects allow simple bookeeping of all potential parents a Container may have.

This object is used by providing all the necessary information for describing the object. This object
gets passed around and candidates are accumulated. Upon calling resolve, all saved candidates are matched
against the information (provided to the constructor). The candidate that has an exact match is returned.
"""

def __init__(self, manager, source, location, namespace, data_type):
self.__source = source
Expand All @@ -24,24 +34,24 @@ def __init__(self, manager, source, location, namespace, data_type):
self.__manager = manager
self.__candidates = list()

@property
def candidates(self):
return self.__candidates

@property
def source(self):
"""The source of the object e.g. file source"""
return self.__source

@property
def location(self):
"""The location of the object. This can be thought of as a unique path"""
return self.__location

@property
def namespace(self):
"""The namespace from which the data_type of this Proxy came from"""
return self.__namespace

@property
def data_type(self):
"""The data_type of Container that should match this Proxy"""
return self.__data_type

@docval({"name": "object", "type": (BaseBuilder, Container), "doc": "the container or builder to get a proxy for"})
Expand Down Expand Up @@ -115,8 +125,12 @@ def __get_proxy_container(self, container):
stack = list()
tmp = container
while tmp is not None:
stack.append(tmp.name)
tmp = tmp.parent
if isinstance(tmp, Proxy):
stack.append(tmp.location)
break
else:
stack.append(tmp.name)
tmp = tmp.parent
loc = "/".join(reversed(stack))
return Proxy(self, container.container_source, loc, ns, dt)

Expand Down Expand Up @@ -523,6 +537,13 @@ def get_attr_value(self, **kwargs):
return None
attr_val = self.__get_override_attr(attr_name, container, manager)
if attr_val is None:
# TODO: A message like this should be used to warn users when an expected attribute
# does not exist on a Container object
#
# if not hasattr(container, attr_name):
# msg = "Container '%s' (%s) does not have attribute '%s'" \
# % (container.name, type(container), attr_name)
# #warnings.warn(msg)
attr_val = getattr(container, attr_name, None)
if attr_val is not None:
attr_val = self.__convert_value(attr_val, spec)
Expand Down
43 changes: 43 additions & 0 deletions tests/unit/form_tests/test_io_hdf5_h5tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from pynwb import NWBHDF5IO
from pynwb.spec import NWBNamespace, NWBGroupSpec, NWBDatasetSpec

from pynwb.ecephys import ElectricalSeries


import tempfile
import warnings
Expand Down Expand Up @@ -400,6 +402,47 @@ def __get_types(self, catalog):
return types


class TestLinkResolution(unittest.TestCase):

def test_link_resolve(self):
print("TEST_LINK_RESOLVE")

nwbfile = NWBFile("source", "a file with header data", "NB123A", '2018-06-01T00:00:00')
device = nwbfile.create_device('device_name', 'source')
electrode_group = nwbfile.create_electrode_group(
name='electrode_group_name',
source='source',
description='desc',
device=device,
location='unknown')
nwbfile.add_electrode(0,
1.0, 2.0, 3.0, # position?
imp=2.718,
location='unknown',
filtering='unknown',
description='desc',
group=electrode_group)
etr = nwbfile.create_electrode_table_region([0], 'etr_name')
for passband in ('theta', 'gamma'):
electrical_series = ElectricalSeries(name=passband + '_phase',
source='ephys_analysis',
data=[1., 2., 3.],
rate=0.0,
electrodes=etr)
nwbfile.add_acquisition(electrical_series)
with NWBHDF5IO(self.path, 'w') as io:
io.write(nwbfile)
with NWBHDF5IO(self.path, 'r') as io:
io.read()

def setUp(self):
self.path = "test_link_resolve.nwb"

def tearDown(self):
if os.path.exists(self.path):
os.remove(self.path)


class NWBHDF5IOMultiFileTest(unittest.TestCase):
"""Tests for h5tools IO tools"""

Expand Down