Skip to content

Commit 44b6950

Browse files
authored
Merge pull request #575 from NeurodataWithoutBorders/bug/recurse_proxy
recurse on Proxy objects
2 parents 432699f + 3b70c95 commit 44b6950

File tree

2 files changed

+70
-6
lines changed

2 files changed

+70
-6
lines changed

src/pynwb/form/build/map.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@
1515

1616

1717
class Proxy(object):
18+
"""
19+
A temporary object to represent a Container. This gets used when resolving the true location of a
20+
Container's parent.
21+
22+
Proxy objects allow simple bookeeping of all potential parents a Container may have.
23+
24+
This object is used by providing all the necessary information for describing the object. This object
25+
gets passed around and candidates are accumulated. Upon calling resolve, all saved candidates are matched
26+
against the information (provided to the constructor). The candidate that has an exact match is returned.
27+
"""
1828

1929
def __init__(self, manager, source, location, namespace, data_type):
2030
self.__source = source
@@ -24,24 +34,24 @@ def __init__(self, manager, source, location, namespace, data_type):
2434
self.__manager = manager
2535
self.__candidates = list()
2636

27-
@property
28-
def candidates(self):
29-
return self.__candidates
30-
3137
@property
3238
def source(self):
39+
"""The source of the object e.g. file source"""
3340
return self.__source
3441

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

3947
@property
4048
def namespace(self):
49+
"""The namespace from which the data_type of this Proxy came from"""
4150
return self.__namespace
4251

4352
@property
4453
def data_type(self):
54+
"""The data_type of Container that should match this Proxy"""
4555
return self.__data_type
4656

4757
@docval({"name": "object", "type": (BaseBuilder, Container), "doc": "the container or builder to get a proxy for"})
@@ -115,8 +125,12 @@ def __get_proxy_container(self, container):
115125
stack = list()
116126
tmp = container
117127
while tmp is not None:
118-
stack.append(tmp.name)
119-
tmp = tmp.parent
128+
if isinstance(tmp, Proxy):
129+
stack.append(tmp.location)
130+
break
131+
else:
132+
stack.append(tmp.name)
133+
tmp = tmp.parent
120134
loc = "/".join(reversed(stack))
121135
return Proxy(self, container.container_source, loc, ns, dt)
122136

@@ -523,6 +537,13 @@ def get_attr_value(self, **kwargs):
523537
return None
524538
attr_val = self.__get_override_attr(attr_name, container, manager)
525539
if attr_val is None:
540+
# TODO: A message like this should be used to warn users when an expected attribute
541+
# does not exist on a Container object
542+
#
543+
# if not hasattr(container, attr_name):
544+
# msg = "Container '%s' (%s) does not have attribute '%s'" \
545+
# % (container.name, type(container), attr_name)
546+
# #warnings.warn(msg)
526547
attr_val = getattr(container, attr_name, None)
527548
if attr_val is not None:
528549
attr_val = self.__convert_value(attr_val, spec)

tests/unit/form_tests/test_io_hdf5_h5tools.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from pynwb import NWBHDF5IO
1313
from pynwb.spec import NWBNamespace, NWBGroupSpec, NWBDatasetSpec
1414

15+
from pynwb.ecephys import ElectricalSeries
16+
1517

1618
import tempfile
1719
import warnings
@@ -400,6 +402,47 @@ def __get_types(self, catalog):
400402
return types
401403

402404

405+
class TestLinkResolution(unittest.TestCase):
406+
407+
def test_link_resolve(self):
408+
print("TEST_LINK_RESOLVE")
409+
410+
nwbfile = NWBFile("source", "a file with header data", "NB123A", '2018-06-01T00:00:00')
411+
device = nwbfile.create_device('device_name', 'source')
412+
electrode_group = nwbfile.create_electrode_group(
413+
name='electrode_group_name',
414+
source='source',
415+
description='desc',
416+
device=device,
417+
location='unknown')
418+
nwbfile.add_electrode(0,
419+
1.0, 2.0, 3.0, # position?
420+
imp=2.718,
421+
location='unknown',
422+
filtering='unknown',
423+
description='desc',
424+
group=electrode_group)
425+
etr = nwbfile.create_electrode_table_region([0], 'etr_name')
426+
for passband in ('theta', 'gamma'):
427+
electrical_series = ElectricalSeries(name=passband + '_phase',
428+
source='ephys_analysis',
429+
data=[1., 2., 3.],
430+
rate=0.0,
431+
electrodes=etr)
432+
nwbfile.add_acquisition(electrical_series)
433+
with NWBHDF5IO(self.path, 'w') as io:
434+
io.write(nwbfile)
435+
with NWBHDF5IO(self.path, 'r') as io:
436+
io.read()
437+
438+
def setUp(self):
439+
self.path = "test_link_resolve.nwb"
440+
441+
def tearDown(self):
442+
if os.path.exists(self.path):
443+
os.remove(self.path)
444+
445+
403446
class NWBHDF5IOMultiFileTest(unittest.TestCase):
404447
"""Tests for h5tools IO tools"""
405448

0 commit comments

Comments
 (0)