mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-06-12 07:42:04 +02:00
code formatting
* auto formatting based on pep8 recommendations * """ for docstrings
This commit is contained in:
parent
7e1a66663a
commit
5bfb55ddd3
4 changed files with 123 additions and 101 deletions
|
@ -8,18 +8,19 @@ import sys
|
||||||
|
|
||||||
|
|
||||||
def trim(s):
|
def trim(s):
|
||||||
'''
|
"""
|
||||||
All repetition of any kind of space is replaced by a single space
|
All repetition of any kind of space is replaced by a single space
|
||||||
and remove trailing space at beginning or end.
|
and remove trailing space at beginning or end.
|
||||||
'''
|
"""
|
||||||
# regex to replace all space groups by a single space
|
# regex to replace all space groups by a single space
|
||||||
# use split() to remove trailing space at beginning/end
|
# use split() to remove trailing space at beginning/end
|
||||||
return re.sub('\s+', ' ', s).strip()
|
return re.sub('\s+', ' ', s).strip()
|
||||||
|
|
||||||
|
|
||||||
def quotesForStrings(valueStr):
|
def quotesForStrings(valueStr):
|
||||||
'''
|
"""
|
||||||
Return the input string with quotes if it cannot be cast into another builtin type.
|
Return the input string with quotes if it cannot be cast into another builtin type.
|
||||||
'''
|
"""
|
||||||
v = valueStr
|
v = valueStr
|
||||||
try:
|
try:
|
||||||
int(valueStr)
|
int(valueStr)
|
||||||
|
@ -52,6 +53,7 @@ if sys.stdin.isatty():
|
||||||
|
|
||||||
inputCmdLineDoc = ''.join([line for line in sys.stdin])
|
inputCmdLineDoc = ''.join([line for line in sys.stdin])
|
||||||
|
|
||||||
|
|
||||||
def convertToLabel(name):
|
def convertToLabel(name):
|
||||||
camelCaseToLabel = re.sub('(.)([A-Z][a-z]+)', r'\1 \2', name)
|
camelCaseToLabel = re.sub('(.)([A-Z][a-z]+)', r'\1 \2', name)
|
||||||
snakeToLabel = ' '.join(word.capitalize() for word in camelCaseToLabel.split('_'))
|
snakeToLabel = ' '.join(word.capitalize() for word in camelCaseToLabel.split('_'))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from meshroom.processGraph import desc
|
from meshroom.processGraph import desc
|
||||||
|
|
||||||
|
|
||||||
class AppendText(desc.CommandLineNode):
|
class AppendText(desc.CommandLineNode):
|
||||||
commandLine = 'cat {inputValue} > {outputValue} && echo {inputTextValue} >> {outputValue}'
|
commandLine = 'cat {inputValue} > {outputValue} && echo {inputTextValue} >> {outputValue}'
|
||||||
input = desc.FileAttribute(
|
input = desc.FileAttribute(
|
||||||
|
|
|
@ -1,37 +1,34 @@
|
||||||
import inspect
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class Attribute:
|
class Attribute:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
isOutput = False
|
isOutput = False
|
||||||
uid = []
|
uid = []
|
||||||
group = 'allParams'
|
group = 'allParams'
|
||||||
commandLine = '{nodeType} --help' # need to be overridden
|
commandLine = '{nodeType} --help' # need to be overridden
|
||||||
def __init__(self):
|
|
||||||
pass
|
def __init__(self, **kwargs):
|
||||||
|
for k, v in kwargs.items():
|
||||||
|
setattr(self, k, v)
|
||||||
|
|
||||||
|
|
||||||
class FileAttribute(Attribute):
|
class FileAttribute(Attribute):
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
for k, v in kwargs.items():
|
super(FileAttribute, self).__init__(**kwargs)
|
||||||
setattr(self, k, v)
|
|
||||||
|
|
||||||
|
|
||||||
class ParamAttribute(Attribute):
|
class ParamAttribute(Attribute):
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
for k, v in kwargs.items():
|
super(ParamAttribute, self).__init__(**kwargs)
|
||||||
setattr(self, k, v)
|
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
internalFolder = '{nodeType}/{uid0}/'
|
internalFolder = '{nodeType}/{uid0}/'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -39,7 +36,5 @@ class Node:
|
||||||
|
|
||||||
|
|
||||||
class CommandLineNode(Node):
|
class CommandLineNode(Node):
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
|
@ -16,15 +16,18 @@ from pprint import pprint
|
||||||
from meshroom import processGraph as pg
|
from meshroom import processGraph as pg
|
||||||
|
|
||||||
# Replace default encoder to support Enums
|
# Replace default encoder to support Enums
|
||||||
DefaultJSONEncoder = json.JSONEncoder # store the original one
|
DefaultJSONEncoder = json.JSONEncoder # store the original one
|
||||||
class MyJSONEncoder(DefaultJSONEncoder): # declare a new one with Enum support
|
|
||||||
|
|
||||||
|
class MyJSONEncoder(DefaultJSONEncoder): # declare a new one with Enum support
|
||||||
def default(self, obj):
|
def default(self, obj):
|
||||||
if isinstance(obj, Enum):
|
if isinstance(obj, Enum):
|
||||||
return obj.name
|
return obj.name
|
||||||
return DefaultJSONEncoder.default(self, obj) # use the default one for all other types
|
return DefaultJSONEncoder.default(self, obj) # use the default one for all other types
|
||||||
json.JSONEncoder = MyJSONEncoder # replace the default implementation with our new one
|
|
||||||
|
|
||||||
|
|
||||||
|
json.JSONEncoder = MyJSONEncoder # replace the default implementation with our new one
|
||||||
|
|
||||||
try:
|
try:
|
||||||
unicode = unicode
|
unicode = unicode
|
||||||
except NameError:
|
except NameError:
|
||||||
|
@ -47,28 +50,30 @@ def hash(v):
|
||||||
|
|
||||||
|
|
||||||
class Attribute:
|
class Attribute:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, name, node, attributeDesc):
|
def __init__(self, name, node, attributeDesc):
|
||||||
self.attrName = name
|
self.attrName = name
|
||||||
self.node = node
|
self.node = node
|
||||||
self._value = attributeDesc.__dict__.get('value', None)
|
self._value = attributeDesc.__dict__.get('value', None)
|
||||||
self.attributeDesc = attributeDesc
|
self.attributeDesc = attributeDesc
|
||||||
|
|
||||||
def aboluteName(self):
|
def absoluteName(self):
|
||||||
return '{}.{}.{}'.format(self.node.graph.name, self.node.name, self.attrName)
|
return '{}.{}.{}'.format(self.node.graph.name, self.node.name, self.attrName)
|
||||||
|
|
||||||
def name(self):
|
def name(self):
|
||||||
'''
|
"""
|
||||||
Name inside the Graph.
|
Name inside the Graph.
|
||||||
'''
|
"""
|
||||||
return '{}.{}'.format(self.node.name, self.attrName)
|
return '{}.{}'.format(self.node.name, self.attrName)
|
||||||
|
|
||||||
def uid(self):
|
def uid(self):
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
if self.attributeDesc.isOutput:
|
if self.attributeDesc.isOutput:
|
||||||
# only dependent of the linked node uid, so it is independant of the cache folder which may be used in the filepath.
|
# only dependent of the linked node uid, so it is independent
|
||||||
|
# from the cache folder which may be used in the filepath.
|
||||||
return self.node.uid()
|
return self.node.uid()
|
||||||
if self.isLink():
|
if self.isLink():
|
||||||
return self.node.graph.edges[self].uid()
|
return self.node.graph.edges[self].uid()
|
||||||
|
@ -77,9 +82,9 @@ class Attribute:
|
||||||
return hash(self._value)
|
return hash(self._value)
|
||||||
|
|
||||||
def isLink(self):
|
def isLink(self):
|
||||||
'''
|
"""
|
||||||
If the attribute is a link to another attribute.
|
If the attribute is a link to another attribute.
|
||||||
'''
|
"""
|
||||||
if self.attributeDesc.isOutput:
|
if self.attributeDesc.isOutput:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
@ -91,11 +96,11 @@ class Attribute:
|
||||||
return self.node.graph.edges[self]
|
return self.node.graph.edges[self]
|
||||||
|
|
||||||
def _applyExpr(self):
|
def _applyExpr(self):
|
||||||
'''
|
"""
|
||||||
For string parameters with an expression (when loaded from file),
|
For string parameters with an expression (when loaded from file),
|
||||||
this function convert the expression into a real edge in the graph
|
this function convert the expression into a real edge in the graph
|
||||||
and clear the string value.
|
and clear the string value.
|
||||||
'''
|
"""
|
||||||
v = self._value
|
v = self._value
|
||||||
if isinstance(v, basestring) and len(v) > 2 and v[0] == '{' and v[-1] == '}':
|
if isinstance(v, basestring) and len(v) > 2 and v[0] == '{' and v[-1] == '}':
|
||||||
# value is a link to another attribute
|
# value is a link to another attribute
|
||||||
|
@ -114,8 +119,8 @@ class Attribute:
|
||||||
|
|
||||||
|
|
||||||
class Status(Enum):
|
class Status(Enum):
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
NONE = 1
|
NONE = 1
|
||||||
SUBMITTED_EXTERN = 2
|
SUBMITTED_EXTERN = 2
|
||||||
SUBMITTED_LOCAL = 3
|
SUBMITTED_LOCAL = 3
|
||||||
|
@ -125,28 +130,32 @@ class Status(Enum):
|
||||||
|
|
||||||
|
|
||||||
class Statistics:
|
class Statistics:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.duration = 0 # computation time set at the end of the execution
|
self.duration = 0 # computation time set at the end of the execution
|
||||||
self.cpuUsage = []
|
self.cpuUsage = []
|
||||||
self.nbCores = 0
|
self.nbCores = 0
|
||||||
self.cpuFreq = 0
|
self.cpuFreq = 0
|
||||||
self.ramUsage = [] # store cpuUsage every minute
|
self.ramUsage = [] # store cpuUsage every minute
|
||||||
self.ramAvailable = 0 # GB
|
self.ramAvailable = 0 # GB
|
||||||
self.vramUsage = []
|
self.vramUsage = []
|
||||||
self.vramAvailable = 0 # GB
|
self.vramAvailable = 0 # GB
|
||||||
self.swapUsage = []
|
self.swapUsage = []
|
||||||
self.swapAvailable = 0
|
self.swapAvailable = 0
|
||||||
|
|
||||||
def toDict(self):
|
def toDict(self):
|
||||||
return self.__dict__
|
return self.__dict__
|
||||||
|
|
||||||
def fromDict(self, d):
|
def fromDict(self, d):
|
||||||
self.__dict__ = d
|
self.__dict__ = d
|
||||||
|
|
||||||
|
|
||||||
class StatusData:
|
class StatusData:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, nodeName, nodeType):
|
def __init__(self, nodeName, nodeType):
|
||||||
self.status = Status.NONE
|
self.status = Status.NONE
|
||||||
self.nodeName = nodeName
|
self.nodeName = nodeName
|
||||||
|
@ -165,10 +174,10 @@ class StatusData:
|
||||||
self.graph = d['graph']
|
self.graph = d['graph']
|
||||||
|
|
||||||
|
|
||||||
bytesPerGiga = 1024.*1024.*1024.
|
bytesPerGiga = 1024. * 1024. * 1024.
|
||||||
|
|
||||||
|
|
||||||
class StatisticsThread(threading.Thread):
|
class StatisticsThread(threading.Thread):
|
||||||
|
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.node = node
|
self.node = node
|
||||||
|
@ -203,11 +212,11 @@ class StatisticsThread(threading.Thread):
|
||||||
if time.time() - self.lastTime > 10:
|
if time.time() - self.lastTime > 10:
|
||||||
self.updateStats()
|
self.updateStats()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
name = None
|
name = None
|
||||||
graph = None
|
graph = None
|
||||||
|
|
||||||
|
@ -256,7 +265,8 @@ class Node:
|
||||||
return self.nodeUid
|
return self.nodeUid
|
||||||
|
|
||||||
def _updateUid(self):
|
def _updateUid(self):
|
||||||
hashInputParams = [(attr.attrName, attr.uid()) for attr in self.attributes.values() if not attr.attributeDesc.isOutput]
|
hashInputParams = [(attr.attrName, attr.uid()) for attr in self.attributes.values() if
|
||||||
|
not attr.attributeDesc.isOutput]
|
||||||
hashInputParams.sort()
|
hashInputParams.sort()
|
||||||
self.nodeUid = hash(tuple([b for a, b in hashInputParams]))
|
self.nodeUid = hash(tuple([b for a, b in hashInputParams]))
|
||||||
return self.nodeUid
|
return self.nodeUid
|
||||||
|
@ -268,8 +278,8 @@ class Node:
|
||||||
attributes = {k: v.getExportValue() for k, v in self.attributes.items()}
|
attributes = {k: v.getExportValue() for k, v in self.attributes.items()}
|
||||||
return {
|
return {
|
||||||
'nodeType': self.nodeType(),
|
'nodeType': self.nodeType(),
|
||||||
'attributes': {k: v for k, v in attributes.items() if v is not None}, # filter empty values
|
'attributes': {k: v for k, v in attributes.items() if v is not None}, # filter empty values
|
||||||
}
|
}
|
||||||
|
|
||||||
def updateInternals(self):
|
def updateInternals(self):
|
||||||
self._updateUid()
|
self._updateUid()
|
||||||
|
@ -285,17 +295,18 @@ class Node:
|
||||||
attr._value = attr.attributeDesc.value.format(
|
attr._value = attr.attributeDesc.value.format(
|
||||||
cache=pg.cacheFolder,
|
cache=pg.cacheFolder,
|
||||||
nodeType=self.nodeType(),
|
nodeType=self.nodeType(),
|
||||||
**self._cmdVars) # self._cmdVars only contains uids at this step
|
**self._cmdVars) # self._cmdVars only contains uids at this step
|
||||||
|
|
||||||
for name, attr in self.attributes.items():
|
for name, attr in self.attributes.items():
|
||||||
linkAttr = attr.getLinkParam()
|
linkAttr = attr.getLinkParam()
|
||||||
v = attr._value
|
v = attr._value
|
||||||
if linkAttr:
|
if linkAttr:
|
||||||
v = linkAttr._value
|
v = linkAttr._value
|
||||||
|
|
||||||
self._cmdVars[name] = '--{name} {value}'.format(name=name, value=v)
|
self._cmdVars[name] = '--{name} {value}'.format(name=name, value=v)
|
||||||
self._cmdVars[name + 'Value'] = str(v)
|
self._cmdVars[name + 'Value'] = str(v)
|
||||||
self._cmdVars[attr.attributeDesc.group] = self._cmdVars.get(attr.attributeDesc.group, '') + ' ' + self._cmdVars[name]
|
self._cmdVars[attr.attributeDesc.group] = self._cmdVars.get(attr.attributeDesc.group, '') + ' ' + \
|
||||||
|
self._cmdVars[name]
|
||||||
|
|
||||||
def internalFolder(self):
|
def internalFolder(self):
|
||||||
return self.nodeDesc.internalFolder.format(nodeType=self.nodeType(), **self._cmdVars)
|
return self.nodeDesc.internalFolder.format(nodeType=self.nodeType(), **self._cmdVars)
|
||||||
|
@ -310,9 +321,9 @@ class Node:
|
||||||
return os.path.join(pg.cacheFolder, self.internalFolder(), 'log')
|
return os.path.join(pg.cacheFolder, self.internalFolder(), 'log')
|
||||||
|
|
||||||
def updateStatusFromCache(self):
|
def updateStatusFromCache(self):
|
||||||
'''
|
"""
|
||||||
Need up-to-date UIDs.
|
Need up-to-date UIDs.
|
||||||
'''
|
"""
|
||||||
statusFile = self.statusFile()
|
statusFile = self.statusFile()
|
||||||
if not os.path.exists(statusFile):
|
if not os.path.exists(statusFile):
|
||||||
self.status.status = Status.NONE
|
self.status.status = Status.NONE
|
||||||
|
@ -322,9 +333,9 @@ class Node:
|
||||||
self.status.fromDict(statusData)
|
self.status.fromDict(statusData)
|
||||||
|
|
||||||
def saveStatusFile(self):
|
def saveStatusFile(self):
|
||||||
'''
|
"""
|
||||||
Need up-to-date UIDs.
|
Need up-to-date UIDs.
|
||||||
'''
|
"""
|
||||||
data = self.status.toDict()
|
data = self.status.toDict()
|
||||||
statusFilepath = self.statusFile()
|
statusFilepath = self.statusFile()
|
||||||
folder = os.path.dirname(statusFilepath)
|
folder = os.path.dirname(statusFilepath)
|
||||||
|
@ -337,7 +348,8 @@ class Node:
|
||||||
|
|
||||||
def upgradeStatusTo(self, newStatus):
|
def upgradeStatusTo(self, newStatus):
|
||||||
if int(newStatus.value) <= int(self.status.status.value):
|
if int(newStatus.value) <= int(self.status.status.value):
|
||||||
print('WARNING: downgrade status on node "{}" from {} to {}'.format(self.name, self.status.status.name, newStatus))
|
print('WARNING: downgrade status on node "{}" from {} to {}'.format(self.name, self.status.status.name,
|
||||||
|
newStatus))
|
||||||
self.status.status = newStatus
|
self.status.status = newStatus
|
||||||
self.saveStatusFile()
|
self.saveStatusFile()
|
||||||
|
|
||||||
|
@ -346,7 +358,7 @@ class Node:
|
||||||
|
|
||||||
def beginSequence(self):
|
def beginSequence(self):
|
||||||
self.upgradeStatusTo(pg.Status.SUBMITTED_LOCAL)
|
self.upgradeStatusTo(pg.Status.SUBMITTED_LOCAL)
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
self.upgradeStatusTo(pg.Status.RUNNING)
|
self.upgradeStatusTo(pg.Status.RUNNING)
|
||||||
statThread = StatisticsThread(self)
|
statThread = StatisticsThread(self)
|
||||||
|
@ -364,14 +376,16 @@ class Node:
|
||||||
statThread.join()
|
statThread.join()
|
||||||
|
|
||||||
self.upgradeStatusTo(pg.Status.SUCCESS)
|
self.upgradeStatusTo(pg.Status.SUCCESS)
|
||||||
|
|
||||||
def endSequence(self):
|
def endSequence(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
WHITE = 0
|
WHITE = 0
|
||||||
GRAY = 1
|
GRAY = 1
|
||||||
BLACK = 2
|
BLACK = 2
|
||||||
|
|
||||||
|
|
||||||
class Visitor:
|
class Visitor:
|
||||||
# def initializeVertex(self, s, g):
|
# def initializeVertex(self, s, g):
|
||||||
# '''is invoked on every vertex of the graph before the start of the graph search.'''
|
# '''is invoked on every vertex of the graph before the start of the graph search.'''
|
||||||
|
@ -380,8 +394,9 @@ class Visitor:
|
||||||
# '''is invoked on the source vertex once before the start of the search.'''
|
# '''is invoked on the source vertex once before the start of the search.'''
|
||||||
# pass
|
# pass
|
||||||
def discoverVertex(self, u, g):
|
def discoverVertex(self, u, g):
|
||||||
'''is invoked when a vertex is encountered for the first time.'''
|
""" is invoked when a vertex is encountered for the first time. """
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# def examineEdge(self, e, g):
|
# def examineEdge(self, e, g):
|
||||||
# '''is invoked on every out-edge of each vertex after it is discovered.'''
|
# '''is invoked on every out-edge of each vertex after it is discovered.'''
|
||||||
# pass
|
# pass
|
||||||
|
@ -398,12 +413,13 @@ class Visitor:
|
||||||
# '''is invoked on the non-tree edges in the graph as well as on each tree edge after its target vertex is finished.'''
|
# '''is invoked on the non-tree edges in the graph as well as on each tree edge after its target vertex is finished.'''
|
||||||
# pass
|
# pass
|
||||||
def finishVertex(self, u, g):
|
def finishVertex(self, u, g):
|
||||||
'''is invoked on a vertex after all of its out edges have been added to the search tree and all of the adjacent vertices have been discovered (but before their out-edges have been examined).'''
|
""" is invoked on a vertex after all of its out edges have been added to the search tree and all of the
|
||||||
|
adjacent vertices have been discovered (but before their out-edges have been examined). """
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Graph:
|
class Graph:
|
||||||
'''
|
"""
|
||||||
_________________ _________________ _________________
|
_________________ _________________ _________________
|
||||||
| | | | | |
|
| | | | | |
|
||||||
| Node A | | Node B | | Node C |
|
| Node A | | Node B | | Node C |
|
||||||
|
@ -416,19 +432,20 @@ class Graph:
|
||||||
nodes = {'A': <nodeA>, 'B': <nodeB>, 'C': <nodeC>}
|
nodes = {'A': <nodeA>, 'B': <nodeB>, 'C': <nodeC>}
|
||||||
edges = {B.input: A.output, C.input: B.output,}
|
edges = {B.input: A.output, C.input: B.output,}
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
'''
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.nodes = {}
|
self.nodes = {}
|
||||||
self.edges = {} # key/input <- value/output, it is organized this way because key/input can have only one connection.
|
self.edges = {} # key/input <- value/output, it is organized this way because key/input can have only one connection.
|
||||||
|
|
||||||
def addNode(self, node, uniqueName=None):
|
def addNode(self, node, uniqueName=None):
|
||||||
if node.graph is not None and node.graph != self:
|
if node.graph is not None and node.graph != self:
|
||||||
raise RuntimeError('Node "{}" cannot be part of the Graph "{}", as it is already part of the other graph "{}".'.format(
|
raise RuntimeError(
|
||||||
node.nodeType(), self.name, node.graph.name))
|
'Node "{}" cannot be part of the Graph "{}", as it is already part of the other graph "{}".'.format(
|
||||||
|
node.nodeType(), self.name, node.graph.name))
|
||||||
if uniqueName:
|
if uniqueName:
|
||||||
assert(uniqueName not in self.nodes)
|
assert uniqueName not in self.nodes
|
||||||
node.name = uniqueName
|
node.name = uniqueName
|
||||||
else:
|
else:
|
||||||
node.name = self._createUniqueNodeName(node.nodeType())
|
node.name = self._createUniqueNodeName(node.nodeType())
|
||||||
|
@ -437,8 +454,15 @@ class Graph:
|
||||||
|
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def addNewNode(self, nodeName, **kwargs):
|
def addNewNode(self, nodeType, **kwargs):
|
||||||
return self.addNode(Node(nodeDesc=nodeName, **kwargs))
|
"""
|
||||||
|
|
||||||
|
:param nodeType:
|
||||||
|
:param kwargs:
|
||||||
|
:return:
|
||||||
|
:rtype: Node
|
||||||
|
"""
|
||||||
|
return self.addNode(Node(nodeDesc=nodeType, **kwargs))
|
||||||
|
|
||||||
def _createUniqueNodeName(self, inputName):
|
def _createUniqueNodeName(self, inputName):
|
||||||
i = 1
|
i = 1
|
||||||
|
@ -449,13 +473,13 @@ class Graph:
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
def getLeaves(self):
|
def getLeaves(self):
|
||||||
nodesWithOuput = set([outputAttr.node for outputAttr in self.edges.values()])
|
nodesWithOutput = set([outputAttr.node for outputAttr in self.edges.values()])
|
||||||
return set(self.nodes.values()) - nodesWithOuput
|
return set(self.nodes.values()) - nodesWithOutput
|
||||||
|
|
||||||
def addEdge(self, outputAttr, inputAttr):
|
def addEdge(self, outputAttr, inputAttr):
|
||||||
assert(isinstance(outputAttr, Attribute))
|
assert isinstance(outputAttr, Attribute)
|
||||||
assert(isinstance(inputAttr, Attribute))
|
assert isinstance(inputAttr, Attribute)
|
||||||
if(outputAttr.node.graph != self or inputAttr.node.graph != self):
|
if outputAttr.node.graph != self or inputAttr.node.graph != self:
|
||||||
raise RuntimeError('The attributes of the edge should be part of a common graph.')
|
raise RuntimeError('The attributes of the edge should be part of a common graph.')
|
||||||
if inputAttr in self.edges:
|
if inputAttr in self.edges:
|
||||||
raise RuntimeError('Input attribute "{}" is already connected.'.format(inputAttr.fullName()))
|
raise RuntimeError('Input attribute "{}" is already connected.'.format(inputAttr.fullName()))
|
||||||
|
@ -477,32 +501,32 @@ class Graph:
|
||||||
return nodeEdges
|
return nodeEdges
|
||||||
|
|
||||||
def dfs(self, visitor, startNodes=None):
|
def dfs(self, visitor, startNodes=None):
|
||||||
nodeChildrens = self._getNodeEdges()
|
nodeChildren = self._getNodeEdges()
|
||||||
colors = {}
|
colors = {}
|
||||||
for u in self.nodes.values():
|
for u in self.nodes.values():
|
||||||
colors[u] = WHITE
|
colors[u] = WHITE
|
||||||
time = 0
|
time = 0
|
||||||
if startNodes:
|
if startNodes:
|
||||||
for startNode in startNodes:
|
for startNode in startNodes:
|
||||||
self.dfsVisit(startNode, visitor, colors, nodeChildrens)
|
self.dfsVisit(startNode, visitor, colors, nodeChildren)
|
||||||
else:
|
else:
|
||||||
leaves = self.getLeaves()
|
leaves = self.getLeaves()
|
||||||
for u in leaves:
|
for u in leaves:
|
||||||
if colors[u] == WHITE:
|
if colors[u] == WHITE:
|
||||||
self.dfsVisit(u, visitor, colors, nodeChildrens)
|
self.dfsVisit(u, visitor, colors, nodeChildren)
|
||||||
|
|
||||||
def dfsVisit(self, u, visitor, colors, nodeChildrens):
|
def dfsVisit(self, u, visitor, colors, nodeChildren):
|
||||||
colors[u] = GRAY
|
colors[u] = GRAY
|
||||||
visitor.discoverVertex(u, self)
|
visitor.discoverVertex(u, self)
|
||||||
# d_time[u] = time = time + 1
|
# d_time[u] = time = time + 1
|
||||||
for v in nodeChildrens[u]:
|
for v in nodeChildren[u]:
|
||||||
if colors[v] == WHITE:
|
if colors[v] == WHITE:
|
||||||
# (u,v) is a tree edge
|
# (u,v) is a tree edge
|
||||||
self.dfsVisit(v, visitor, colors, nodeChildrens) # TODO: avoid recursion
|
self.dfsVisit(v, visitor, colors, nodeChildren) # TODO: avoid recursion
|
||||||
elif colors[v] == GRAY:
|
elif colors[v] == GRAY:
|
||||||
pass # (u,v) is a back edge
|
pass # (u,v) is a back edge
|
||||||
elif colors[v] == BLACK:
|
elif colors[v] == BLACK:
|
||||||
pass # (u,v) is a cross or forward edge
|
pass # (u,v) is a cross or forward edge
|
||||||
colors[u] = BLACK
|
colors[u] = BLACK
|
||||||
visitor.finishVertex(u, self)
|
visitor.finishVertex(u, self)
|
||||||
|
|
||||||
|
@ -516,6 +540,7 @@ class Graph:
|
||||||
def dfsNodesToProcess(self, startNodes=None):
|
def dfsNodesToProcess(self, startNodes=None):
|
||||||
nodes = []
|
nodes = []
|
||||||
visitor = Visitor()
|
visitor = Visitor()
|
||||||
|
|
||||||
def finishVertex(vertex, graph):
|
def finishVertex(vertex, graph):
|
||||||
if vertex.status.status in (Status.SUBMITTED_EXTERN,
|
if vertex.status.status in (Status.SUBMITTED_EXTERN,
|
||||||
Status.SUBMITTED_LOCAL):
|
Status.SUBMITTED_LOCAL):
|
||||||
|
@ -524,6 +549,7 @@ class Graph:
|
||||||
print('WARNING: node "{}" is already running.'.format(vertex.name))
|
print('WARNING: node "{}" is already running.'.format(vertex.name))
|
||||||
if vertex.status.status is not Status.SUCCESS:
|
if vertex.status.status is not Status.SUCCESS:
|
||||||
nodes.append(vertex)
|
nodes.append(vertex)
|
||||||
|
|
||||||
visitor.finishVertex = finishVertex
|
visitor.finishVertex = finishVertex
|
||||||
self.dfs(visitor=visitor, startNodes=startNodes)
|
self.dfs(visitor=visitor, startNodes=startNodes)
|
||||||
return nodes
|
return nodes
|
||||||
|
@ -536,8 +562,8 @@ class Graph:
|
||||||
return {k: node.toDict() for k, node in self.nodes.items()}
|
return {k: node.toDict() for k, node in self.nodes.items()}
|
||||||
|
|
||||||
def save(self, filepath):
|
def save(self, filepath):
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
data = self.toDict()
|
data = self.toDict()
|
||||||
pprint(data)
|
pprint(data)
|
||||||
with open(filepath, 'w') as jsonFile:
|
with open(filepath, 'w') as jsonFile:
|
||||||
|
@ -558,9 +584,8 @@ class Graph:
|
||||||
|
|
||||||
|
|
||||||
def loadGraph(filepath):
|
def loadGraph(filepath):
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
graphData = None
|
|
||||||
with open(filepath) as jsonFile:
|
with open(filepath) as jsonFile:
|
||||||
graphData = json.load(jsonFile)
|
graphData = json.load(jsonFile)
|
||||||
if not isinstance(graphData, dict):
|
if not isinstance(graphData, dict):
|
||||||
|
@ -577,8 +602,8 @@ def loadGraph(filepath):
|
||||||
|
|
||||||
|
|
||||||
def execute(graph, startNodes=None, force=False):
|
def execute(graph, startNodes=None, force=False):
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
if force:
|
if force:
|
||||||
nodes = graph.dfsNodesOnFinish(startNodes=startNodes)
|
nodes = graph.dfsNodesOnFinish(startNodes=startNodes)
|
||||||
else:
|
else:
|
||||||
|
@ -597,4 +622,3 @@ def execute(graph, startNodes=None, force=False):
|
||||||
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
node.endSequence()
|
node.endSequence()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue