Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions meshroom/core/attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@
from meshroom.core.graph import Edge


def _captureExpressionTemplates(attr, value):
"""
Recursively set _expressionTemplate on output expression attributes from their loaded values.
Preserves the serialized expression template so that description changes on the node type
only affect new nodes, not existing ones loaded from a project file.
"""
if attr.desc.isExpression and isinstance(value, str):
attr._expressionTemplate = value
elif isinstance(attr, GroupAttribute) and isinstance(value, dict):
for key, child_value in value.items():
try:
child_attr = attr._value.get(key)
if child_attr is not None:
_captureExpressionTemplates(child_attr, child_value)
except (KeyError, AttributeError):
pass


def attributeFactory(description: str, value, isOutput: bool, node, root=None, parent=None):
"""
Create an Attribute based on description type.
Expand All @@ -39,6 +57,10 @@ def attributeFactory(description: str, value, isOutput: bool, node, root=None, p
attr: Attribute = description.instanceType(node, description, isOutput, root, parent)
if value is not None:
attr._setValue(value)
# For output expression attributes loaded from a file, store the expression template
# so that description changes on the node type only affect new nodes.
if isOutput:
_captureExpressionTemplates(attr, value)
else:
attr.resetToDefaultValue()
# Only connect slot that reacts to value change once initial value has been set.
Expand Down Expand Up @@ -90,6 +112,10 @@ def __init__(self, node, attributeDesc: desc.Attribute, isOutput: bool, root=Non
self._value = None
self._keyValues = None # list of pairs (key, value) for keyable attribute
self._linkExpression: Optional[str] = None
# Expression template stored when loading from a saved project file.
# When set, this overrides the descriptor's expression for this node instance,
# so that description changes on the node type only affect new nodes.
self._expressionTemplate: Optional[str] = None
self._initValue()

def _getFullName(self) -> str:
Expand Down Expand Up @@ -350,6 +376,8 @@ def getSerializedValue(self):
if self.keyable:
return self._keyValues.getSerializedValues()
if self.isOutput and self._desc.isExpression:
if self._expressionTemplate is not None:
return self._expressionTemplate
return self.getDefaultValue()
return self.value

Expand Down
5 changes: 4 additions & 1 deletion meshroom/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -1265,7 +1265,10 @@ def _buildAttributeExpVars(expVars, name, attr):
# (the expression may refer to other attributes that are not defined)
if attr.enabled:
try:
defaultValue = attr.getDefaultValue()
# Use the expression template stored when loading from a file (if any),
# so that description changes on the node type only affect new nodes.
defaultValue = attr._expressionTemplate if attr._expressionTemplate is not None \
else attr.getDefaultValue()
except AttributeError:
# If we load an old scene, the lambda associated to the 'value' could try to
# access other params that could not exist yet
Expand Down
Loading