mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-05-22 21:46:28 +02:00
[graph] automatically trigger Graph updates
* update graph internals / node status when: - an input attribute is set - edges are added/removed * add GraphModification context manager to group graph updates
This commit is contained in:
parent
a0cdc65143
commit
5e4b26fa5e
1 changed files with 67 additions and 18 deletions
|
@ -11,6 +11,7 @@ import shutil
|
|||
import time
|
||||
import uuid
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
from enum import Enum # available by default in python3. For python2: "pip install enum34"
|
||||
import logging
|
||||
|
||||
|
@ -48,6 +49,29 @@ else:
|
|||
basestring = basestring
|
||||
|
||||
|
||||
@contextmanager
|
||||
def GraphModification(graph):
|
||||
"""
|
||||
A Context Manager that can be used to trigger only one Graph update
|
||||
for a group of several modifications.
|
||||
GraphModifications can be nested.
|
||||
"""
|
||||
if not isinstance(graph, Graph):
|
||||
raise ValueError("GraphModification expects a Graph instance")
|
||||
# Store update policy
|
||||
enabled = graph.updateEnabled
|
||||
# Disable graph update for nested block
|
||||
# (does nothing if already disabled)
|
||||
graph.updateEnabled = False
|
||||
try:
|
||||
yield # Execute nested block
|
||||
except Exception:
|
||||
raise
|
||||
finally:
|
||||
# Restore update policy
|
||||
graph.updateEnabled = enabled
|
||||
|
||||
|
||||
def hash(v):
|
||||
hashObject = hashlib.sha1(str(v).encode('utf-8'))
|
||||
return hashObject.hexdigest()
|
||||
|
@ -120,6 +144,14 @@ class Attribute(BaseObject):
|
|||
if self._value == value:
|
||||
return
|
||||
self._value = value
|
||||
# Request graph update when input parameter value is set
|
||||
# and parent node belongs to a graph
|
||||
# Output attributes value are set internally during the update process,
|
||||
# which is why we don't trigger any update in this case
|
||||
# TODO: update only the nodes impacted by this change
|
||||
# TODO: only update the graph if this attribute participates to a UID
|
||||
if self.node.graph and self.attributeDesc.isInput:
|
||||
self.node.graph.update()
|
||||
self.valueChanged.emit()
|
||||
|
||||
@property
|
||||
|
@ -409,8 +441,9 @@ class Node(BaseObject):
|
|||
self.attributesPerUid[uidIndex].add(attr)
|
||||
|
||||
def _applyExpr(self):
|
||||
for attr in self._attributes:
|
||||
attr._applyExpr()
|
||||
with GraphModification(self.graph):
|
||||
for attr in self._attributes:
|
||||
attr._applyExpr()
|
||||
|
||||
@property
|
||||
def nodeType(self):
|
||||
|
@ -690,6 +723,8 @@ class Graph(BaseObject):
|
|||
def __init__(self, name, parent=None):
|
||||
super(Graph, self).__init__(parent)
|
||||
self.name = name
|
||||
self._updateEnabled = True
|
||||
self._updateRequested = False
|
||||
self._nodes = DictModel(keyAttrName='name', parent=self)
|
||||
self._edges = DictModel(keyAttrName='dst', parent=self) # use dst attribute as unique key since it can only have one input connection
|
||||
self._cacheDir = ''
|
||||
|
@ -718,6 +753,18 @@ class Graph(BaseObject):
|
|||
# Create graph edges by resolving attributes expressions
|
||||
self._applyExpr()
|
||||
|
||||
@property
|
||||
def updateEnabled(self):
|
||||
return self._updateEnabled
|
||||
|
||||
@updateEnabled.setter
|
||||
def updateEnabled(self, enabled):
|
||||
self._updateEnabled = enabled
|
||||
if enabled and self._updateRequested:
|
||||
# Trigger an update if requested while disabled
|
||||
self.update()
|
||||
self._updateRequested = False
|
||||
|
||||
def _addNode(self, node, uniqueName):
|
||||
"""
|
||||
Internal method to add the given node to this Graph, with the given name (must be unique).
|
||||
|
@ -734,10 +781,6 @@ class Graph(BaseObject):
|
|||
self._nodes.add(node)
|
||||
self.stopExecutionRequested.connect(node.stopProcess)
|
||||
|
||||
# Trigger internal update when an attribute is modified
|
||||
for attr in node.attributes: # type: Attribute
|
||||
attr.valueChanged.connect(self.updateInternals)
|
||||
|
||||
def addNode(self, node, uniqueName=None):
|
||||
"""
|
||||
Add the given node to this Graph with an optional unique name,
|
||||
|
@ -763,15 +806,15 @@ class Graph(BaseObject):
|
|||
|
||||
inEdges = {}
|
||||
outEdges = {}
|
||||
for attr in node._attributes:
|
||||
for edge in self.outEdges(attr):
|
||||
self.edges.remove(edge)
|
||||
outEdges[edge.dst.fullName()] = edge.src.fullName()
|
||||
if attr in self.edges.keys():
|
||||
edge = self.edges.pop(attr)
|
||||
inEdges[edge.dst.fullName()] = edge.src.fullName()
|
||||
with GraphModification(self):
|
||||
for attr in node._attributes:
|
||||
for edge in self.outEdges(attr):
|
||||
self.edges.remove(edge)
|
||||
outEdges[edge.dst.fullName()] = edge.src.fullName()
|
||||
if attr in self.edges.keys():
|
||||
edge = self.edges.pop(attr)
|
||||
inEdges[edge.dst.fullName()] = edge.src.fullName()
|
||||
|
||||
self.updateInternals()
|
||||
return inEdges, outEdges
|
||||
|
||||
@Slot(str, result=Node)
|
||||
|
@ -838,11 +881,13 @@ class Graph(BaseObject):
|
|||
self.edges.add(edge)
|
||||
dstAttr.valueChanged.emit()
|
||||
dstAttr.isLinkChanged.emit()
|
||||
self.update()
|
||||
return edge
|
||||
|
||||
def addEdges(self, *edges):
|
||||
for edge in edges:
|
||||
self.addEdge(*edge)
|
||||
with GraphModification(self):
|
||||
for edge in edges:
|
||||
self.addEdge(*edge)
|
||||
|
||||
def removeEdge(self, dstAttr):
|
||||
if dstAttr not in self.edges.keys():
|
||||
|
@ -850,6 +895,7 @@ class Graph(BaseObject):
|
|||
edge = self.edges.pop(dstAttr)
|
||||
dstAttr.valueChanged.emit()
|
||||
dstAttr.isLinkChanged.emit()
|
||||
self.update()
|
||||
return edge
|
||||
|
||||
def getDepth(self, node):
|
||||
|
@ -1028,8 +1074,9 @@ class Graph(BaseObject):
|
|||
return flowEdges
|
||||
|
||||
def _applyExpr(self):
|
||||
for node in self._nodes:
|
||||
node._applyExpr()
|
||||
with GraphModification(self):
|
||||
for node in self._nodes:
|
||||
node._applyExpr()
|
||||
|
||||
def toDict(self):
|
||||
return {k: node.toDict() for k, node in self._nodes.objects.items()}
|
||||
|
@ -1060,6 +1107,8 @@ class Graph(BaseObject):
|
|||
node.updateStatisticsFromCache()
|
||||
|
||||
def update(self):
|
||||
if not self._updateEnabled:
|
||||
self._updateRequested = True
|
||||
self.updateInternals()
|
||||
self.updateStatusFromCache()
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue