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

rewrite parent registry & repo init #95

Merged
merged 2 commits into from
Jun 30, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
66 changes: 17 additions & 49 deletions python/lsst/daf/persistence/butler.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,56 +532,24 @@ def __init__(self, root=None, mapper=None, inputs=None, outputs=None, **mapperAr

self._setRepoDataTags()

for repoData in reversed(repoDataList):
self._setParentRegistry(repoData)
repoData.repo = Repository(repoData)

def _setParentRegistry(self, repoData):
"""Try to get a parent registry that can be used by this repository. To be usable the repository must
"match", meaning the mapper in the passed-in repo is the same type as the mapper in the parent.
"""

def getParentRegsitry(repoData, context):
"""Get the first found registry that matches the the passed-in repo.

Parameters
----------
repoData : RepoData
The RepoData for the repository for which we are searching for a
parent registry.

Returns
-------
Registry or None
A registry from a parent if one can be found, or None.

Raises
------
RuntimeError
Indicates a butler init order problem, all parents should be initialized before child
repositories, so this function should be able to get any parent of any child repo.
"""
if id(self) in context:
return None
else:
context.add(id(self))
for parentRepoData in repoData.getParentRepoDatas():
if parentRepoData.cfg.mapper == repoData.cfg.mapper:
if parentRepoData.repo is None:
self.log.debug(
"_getParentRegistry: Parent {} of new repo {} not yet created, ignoring.".format(
parentRepoData, repoData))
else:
parentRegistry = parentRepoData.repo.getRegistry()
if parentRegistry:
return parentRegistry
else:
parentRegistry = getParentRegsitry(parentRepoData, context)
if parentRegistry:
return parentRegistry
return None
for repoData in repoDataList:
self._initRepo(repoData)

repoData.repoData.parentRegistry = getParentRegsitry(repoData.repoData, set())
def _initRepo(self, repoData):
if repoData.repo is not None:
# this repository may have already been initialized by its children, in which case there is
# nothing more to do.
return
for parentRepoData in repoData.parentRepoDatas:
if parentRepoData.cfg.mapper != repoData.cfg.mapper:
continue
if parentRepoData.repo is None:
self._initRepo(parentRepoData)
parentRegistry = parentRepoData.repo.getRegistry()
repoData.parentRegistry = parentRegistry if parentRegistry else parentRepoData.parentRegistry
if repoData.parentRegistry:
break
repoData.repo = Repository(repoData)

def _processInputArguments(self, root=None, mapper=None, inputs=None, outputs=None, **mapperArgs):
"""Process, verify, and standardize the input arguments.
Expand Down
2 changes: 2 additions & 0 deletions python/lsst/daf/persistence/registries.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ def __init__(self, location):
if os.path.exists(location):
conn = sqlite3.connect(location)
conn.text_factory = str
self.root = location
else:
conn = None
SqlRegistry.__init__(self, conn)
Expand All @@ -441,6 +442,7 @@ def __init__(self, location):
self._config = config
conn = pgsql.connect(host=config["host"], port=config["port"], database=config["database"],
user=config["user"], password=config["password"])
self.root = location
SqlRegistry.__init__(self, conn)

@staticmethod
Expand Down
40 changes: 40 additions & 0 deletions tests/test_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,46 @@ def testCreateAggregateAndLoadingAChild(self):
self.assertEqual(objB, butlerD.get('foo', {'val': 2}))


class TestDiamondPattern(unittest.TestCase):
"""A test case for when a butler is created with an output repository and two input repositories that have
a common parent; verifies that the parent's registry is loaded as the parentRegistry of the output
repository.
"""
@staticmethod
def makeRegistry(location, name):
conn = sqlite3.connect(location)
conn.execute("CREATE TABLE {name} (real)".format(name=name))
conn.commit()
conn.close()

def setUp(self):
self.testDir = tempfile.mkdtemp(dir=ROOT, prefix="TestDiamondPattern-")

def tearDown(self):
if os.path.exists(self.testDir):
shutil.rmtree(self.testDir)

def test(self):
repoARoot = os.path.join(self.testDir, 'repoA')
butler = dp.Butler(outputs={'root': repoARoot, 'mapper': ParentRepoTestMapper})
self.makeRegistry(os.path.join(repoARoot, 'registry.sqlite3'), 'repoA')
del butler

repoBRoot = os.path.join(self.testDir, 'repoB')
butlerB = dp.Butler(inputs=repoARoot, outputs=repoBRoot)
del butlerB

repoCRoot = os.path.join(self.testDir, 'repoC')
butlerC = dp.Butler(inputs=repoARoot, outputs=repoCRoot)
del butlerC

repoDRoot = os.path.join(self.testDir, 'repoD')
butlerD = dp.Butler(inputs=(repoBRoot, repoCRoot), outputs=repoDRoot)

self.assertEqual(1, len(butlerD._repos.outputs()))
self.assertEqual(os.path.dirname(butlerD._repos.outputs()[0].parentRegistry.root), repoARoot)


class TestMasking(unittest.TestCase):
"""A test case for the repository classes.

Expand Down