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

Add internal attributes in "Notes" tab #1744

Merged
merged 19 commits into from
Mar 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9bc9e2c
Add "Notes" tab with "comment"/"invalid comment" attributes
cbentejac Oct 12, 2022
330382a
Add "label" as an internal attribute
cbentejac Aug 2, 2022
21d01ac
Add "color" as an internal attribute
cbentejac Aug 2, 2022
930af07
[core] Correctly load internalAttributes in compatibility mode
cbentejac Sep 8, 2022
fe3a076
[core] Do not save default internal attributes in template mode
cbentejac Oct 12, 2022
cc3c19b
[core] internal attributes: update descriptions and declare "invalida…
fabiencastan Oct 10, 2022
b645db9
[core] Include internal attributes in the UIDs computation
cbentejac Oct 11, 2022
1015ea4
[ui] Add an icon and tooltip on a node's header if it has a comment
cbentejac Oct 13, 2022
3689c12
[core] Check existence of group or list attributes correctly
cbentejac Oct 13, 2022
91db765
[core] Don't write "internalInputs" entry in templates if there are o…
cbentejac Oct 24, 2022
b470078
[tests] Add checks on internal attributes in the templatesVersion test
cbentejac Oct 24, 2022
7688b94
[core] Raise compatibility issue if nodes miss invalidating internal …
cbentejac Nov 18, 2022
835e396
[core] Remove reference to pyCompatibility
cbentejac Dec 7, 2022
3bc9445
[core] Internal attributes: move "invalidation" before "comment"
cbentejac Dec 15, 2022
492e4d5
[core] Add property for the invalidation message from internal attrib…
cbentejac Dec 15, 2022
4b7a548
Notify changes in internal attributes' properties
cbentejac Dec 15, 2022
6381371
Display the invalidation and comment messages in the internal attribu…
cbentejac Dec 15, 2022
311ab9c
[core] Add a property to ignore an attribute during the UID computation
cbentejac Feb 17, 2023
25c12bb
[core] Node: hasInternalAttribute does not support groups and lists
fabiencastan Feb 22, 2023
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
15 changes: 15 additions & 0 deletions meshroom/core/attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ def setEnabled(self, v):
self._enabled = v
self.enabledChanged.emit()

def getUidIgnoreValue(self):
""" Value for which the attribute should be ignored during the UID computation. """
return self.attributeDesc.uidIgnoreValue

def _get_value(self):
if self.isLink:
return self.getLinkParam().value
Expand All @@ -168,6 +172,10 @@ def _set_value(self, value):
# TODO: only update the graph if this attribute participates to a UID
if self.isInput:
self.requestGraphUpdate()
# TODO: only call update of the node if the attribute is internal
# Internal attributes are set as inputs
self.requestNodeUpdate()

self.valueChanged.emit()

def upgradeValue(self, exportedValue):
Expand All @@ -181,6 +189,12 @@ def requestGraphUpdate(self):
self.node.graph.markNodesDirty(self.node)
self.node.graph.update()

def requestNodeUpdate(self):
# Update specific node information that do not affect the rest of the graph
# (like internal attributes)
if self.node:
self.node.updateInternalAttributes()

@property
def isOutput(self):
return self._isOutput
Expand Down Expand Up @@ -323,6 +337,7 @@ def updateInternals(self):
node = Property(BaseObject, node.fget, constant=True)
enabledChanged = Signal()
enabled = Property(bool, getEnabled, setEnabled, notify=enabledChanged)
uidIgnoreValue = Property(Variant, getUidIgnoreValue, constant=True)


def raiseIfLink(func):
Expand Down
64 changes: 59 additions & 5 deletions meshroom/core/desc.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Attribute(BaseObject):
"""
"""

def __init__(self, name, label, description, value, advanced, semantic, uid, group, enabled):
def __init__(self, name, label, description, value, advanced, semantic, uid, group, enabled, uidIgnoreValue=None):
super(Attribute, self).__init__()
self._name = name
self._label = label
Expand All @@ -25,6 +25,7 @@ def __init__(self, name, label, description, value, advanced, semantic, uid, gro
self._advanced = advanced
self._enabled = enabled
self._semantic = semantic
self._uidIgnoreValue = uidIgnoreValue

name = Property(str, lambda self: self._name, constant=True)
label = Property(str, lambda self: self._label, constant=True)
Expand All @@ -35,6 +36,7 @@ def __init__(self, name, label, description, value, advanced, semantic, uid, gro
advanced = Property(bool, lambda self: self._advanced, constant=True)
enabled = Property(Variant, lambda self: self._enabled, constant=True)
semantic = Property(str, lambda self: self._semantic, constant=True)
uidIgnoreValue = Property(Variant, lambda self: self._uidIgnoreValue, constant=True)
type = Property(str, lambda self: self.__class__.__name__, constant=True)

def validateValue(self, value):
Expand Down Expand Up @@ -201,8 +203,9 @@ def retrieveChildrenUids(self):
class Param(Attribute):
"""
"""
def __init__(self, name, label, description, value, uid, group, advanced, semantic, enabled):
super(Param, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
def __init__(self, name, label, description, value, uid, group, advanced, semantic, enabled, uidIgnoreValue=None):
super(Param, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled,
uidIgnoreValue=uidIgnoreValue)


class File(Attribute):
Expand Down Expand Up @@ -329,8 +332,9 @@ def checkValueTypes(self):
class StringParam(Param):
"""
"""
def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', enabled=True):
super(StringParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', enabled=True, uidIgnoreValue=None):
super(StringParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled,
uidIgnoreValue=uidIgnoreValue)

def validateValue(self, value):
if not isinstance(value, str):
Expand All @@ -343,6 +347,19 @@ def checkValueTypes(self):
return ""


class ColorParam(Param):
"""
"""
def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', enabled=True):
super(ColorParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)

def validateValue(self, value):
if not isinstance(value, str) or len(value.split(" ")) > 1:
raise ValueError('ColorParam value should be a string containing either an SVG name or an hexadecimal '
'color code (param: {}, value: {}, type: {})'.format(self.name, value, type(value)))
return value


class Level(Enum):
NONE = 0
NORMAL = 1
Expand Down Expand Up @@ -485,6 +502,43 @@ class Node(object):
ram = Level.NORMAL
packageName = ''
packageVersion = ''
internalInputs = [
StringParam(
name="invalidation",
label="Invalidation Message",
description="A message that will invalidate the node's output folder.\n"
"This is useful for development, we can invalidate the output of the node when we modify the code.\n"
"It is displayed in bold font in the invalidation/comment messages tooltip.",
value="",
semantic="multiline",
uid=[0],
advanced=True,
uidIgnoreValue="", # If the invalidation string is empty, it does not participate to the node's UID
),
StringParam(
name="comment",
label="Comments",
description="User comments describing this specific node instance.\n"
"It is displayed in regular font in the invalidation/comment messages tooltip.",
value="",
semantic="multiline",
uid=[],
),
StringParam(
name="label",
label="Node's Label",
description="Customize the default label (to replace the technical name of the node instance).",
value="",
uid=[],
),
ColorParam(
name="color",
label="Color",
description="Custom color for the node (SVG name or hexadecimal code).",
value="",
uid=[],
)
]
inputs = []
outputs = []
size = StaticNodeSize(1)
Expand Down
36 changes: 33 additions & 3 deletions meshroom/core/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,9 +687,24 @@ def attribute(self, fullName):
# type: (str) -> Attribute
"""
Return the attribute identified by the unique name 'fullName'.
If it does not exist, return None.
"""
node, attribute = fullName.split('.', 1)
return self.node(node).attribute(attribute)
if self.node(node).hasAttribute(attribute):
return self.node(node).attribute(attribute)
return None

@Slot(str, result=Attribute)
def internalAttribute(self, fullName):
# type: (str) -> Attribute
"""
Return the internal attribute identified by the unique name 'fullName'.
If it does not exist, return None.
"""
node, attribute = fullName.split('.', 1)
if self.node(node).hasInternalAttribute(attribute):
return self.node(node).internalAttribute(attribute)
return None

@staticmethod
def getNodeIndexFromName(name):
Expand Down Expand Up @@ -1221,27 +1236,42 @@ def save(self, filepath=None, setupProjectFile=True, template=False):

def getNonDefaultInputAttributes(self):
"""
Instead of getting all the inputs attribute keys, only get the keys of
Instead of getting all the inputs and internal attribute keys, only get the keys of
the attributes whose value is not the default one.
The output attributes, UIDs, parallelization parameters and internal folder are
not relevant for templates, so they are explicitly removed from the returned dictionary.

Returns:
dict: self.toDict() with the output attributes, UIDs, parallelization parameters, internal folder
and input attributes with default values removed
and input/internal attributes with default values removed
"""
graph = self.toDict()
for nodeName in graph.keys():
node = self.node(nodeName)

inputKeys = list(graph[nodeName]["inputs"].keys())

internalInputKeys = []
internalInputs = graph[nodeName].get("internalInputs", None)
if internalInputs:
internalInputKeys = list(internalInputs.keys())

for attrName in inputKeys:
attribute = node.attribute(attrName)
# check that attribute is not a link for choice attributes
if attribute.isDefault and not attribute.isLink:
del graph[nodeName]["inputs"][attrName]

for attrName in internalInputKeys:
attribute = node.internalAttribute(attrName)
# check that internal attribute is not a link for choice attributes
if attribute.isDefault and not attribute.isLink:
del graph[nodeName]["internalInputs"][attrName]

# If all the internal attributes are set to their default values, remove the entry
if len(graph[nodeName]["internalInputs"]) == 0:
del graph[nodeName]["internalInputs"]

del graph[nodeName]["outputs"]
del graph[nodeName]["uids"]
del graph[nodeName]["internalFolder"]
Expand Down
Loading