Source code for smv.modulesvisitor
# This file is licensed under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from smv.utils import lazy_property
from collections import OrderedDict
import sys
if sys.version_info >= (3, 0):
import queue
else:
import Queue as queue
[docs]class ModulesVisitor(object):
"""Provides way to do depth and breadth first visit to the sub-graph
of modules given a set of roots
"""
def __init__(self, roots):
self.roots = roots
self.queue = self._build_queue(roots)
def _build_dict(self, roots, un_persisted_only):
"""Create a breadth first ordered dict for multiple roots,
when un_persisted_only==False
including all the modules up stream of the roots
otherwise
only include modules needed to calculate roots, in other
words if a module is persisted already, its upper steam
modules will be excluded
"""
# to traversal the graph in bfs order
_working_queue = queue.Queue()
for m in roots:
_working_queue.put(m)
# keep a distinct sorted list of nodes with root always in front of leafs
_sorted = OrderedDict()
for m in roots:
_sorted.update({m: True})
while(not _working_queue.empty()):
mod = _working_queue.get()
if(not un_persisted_only or not mod._is_persisted()):
for m in mod.resolvedRequiresDS:
# regardless whether seen before, add to queue, so not drop
# any dependency which may change the ordering of the result
_working_queue.put(m)
# if in the result list already, remove the old, add the new,
# to make sure leafs always later
if (m in _sorted):
_sorted.pop(m)
_sorted.update({m: True})
return _sorted
def _build_queue(self, roots):
"""Create a depth first queue for multiple roots"""
_sorted = self._build_dict(roots, False)
# reverse the result before output to make leafs first
return [m for m in reversed(_sorted)]
@lazy_property
def modules_needed_for_run(self):
"""For each run, if a module is persisted, all its ancestors
are not even needed to be visited. This method creates a
sub-list for the queue which are needed for current run
"""
_sorted = self._build_dict(self.roots, True)
return [m for m in reversed(_sorted)]
[docs] def dfs_visit(self, action, state, need_to_run_only=False):
"""Depth first visit"""
if (need_to_run_only):
l = self.modules_needed_for_run
else:
l = self.queue
for m in l:
action(m, state)
[docs] def bfs_visit(self, action, state, need_to_run_only=False):
"""Breadth first visit"""
if (need_to_run_only):
l = self.modules_needed_for_run
else:
l = self.queue
for m in reversed(l):
action(m, state)