mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-05-29 08:56:33 +02:00
[graph] handle ListAttribute and GroupAttribute
This commit is contained in:
parent
d0c0a28d5d
commit
e42e04fd9d
1 changed files with 139 additions and 16 deletions
|
@ -17,7 +17,7 @@ import logging
|
||||||
from . import stats
|
from . import stats
|
||||||
from . import desc
|
from . import desc
|
||||||
from meshroom import core as pg
|
from meshroom import core as pg
|
||||||
from meshroom.common import BaseObject, Model, Slot, Signal, Property
|
from meshroom.common import BaseObject, DictModel, Slot, Signal, Property, Variant, ListModel
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -53,6 +53,30 @@ def hash(v):
|
||||||
return hashObject.hexdigest()
|
return hashObject.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def attribute_factory(description, name, value, node, parent=None):
|
||||||
|
# type: (desc.Attribute, str, (), Node, Attribute) -> Attribute
|
||||||
|
"""
|
||||||
|
Create an Attribute based on description type.
|
||||||
|
|
||||||
|
:param description: the Attribute description
|
||||||
|
:param name: name of the Attribute
|
||||||
|
:param value: value of the Attribute. Will be set if not None.
|
||||||
|
:param node: node owning the Attribute. Note that the created Attribute is not added to Node's attributes
|
||||||
|
:param parent: (optional) parent Attribute (must be ListAttribute or GroupAttribute)
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if isinstance(description, pg.desc.GroupAttribute):
|
||||||
|
cls = GroupAttribute
|
||||||
|
elif isinstance(description, pg.desc.ListAttribute):
|
||||||
|
cls = ListAttribute
|
||||||
|
else:
|
||||||
|
cls = Attribute
|
||||||
|
attr = cls(name, node, description, parent=parent)
|
||||||
|
if value is not None:
|
||||||
|
attr.value = value
|
||||||
|
return attr
|
||||||
|
|
||||||
|
|
||||||
class Attribute(BaseObject):
|
class Attribute(BaseObject):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
@ -71,6 +95,10 @@ class Attribute(BaseObject):
|
||||||
|
|
||||||
def fullName(self):
|
def fullName(self):
|
||||||
""" Name inside the Graph: nodeName.name """
|
""" Name inside the Graph: nodeName.name """
|
||||||
|
if isinstance(self.parent(), ListAttribute):
|
||||||
|
return '{}[{}]'.format(self.parent().fullName(), self.parent().index(self))
|
||||||
|
elif isinstance(self.parent(), GroupAttribute):
|
||||||
|
return '{}.{}'.format(self.parent().fullName(), self._name)
|
||||||
return '{}.{}'.format(self.node.name, self._name)
|
return '{}.{}'.format(self.node.name, self._name)
|
||||||
|
|
||||||
def getName(self):
|
def getName(self):
|
||||||
|
@ -80,12 +108,10 @@ class Attribute(BaseObject):
|
||||||
def getLabel(self):
|
def getLabel(self):
|
||||||
return self._label
|
return self._label
|
||||||
|
|
||||||
@property
|
def _get_value(self):
|
||||||
def value(self):
|
return self.getLinkParam().value if self.isLink else self._value
|
||||||
return self._value
|
|
||||||
|
|
||||||
@value.setter
|
def _set_value(self, value):
|
||||||
def value(self, value):
|
|
||||||
if self._value == value:
|
if self._value == value:
|
||||||
return
|
return
|
||||||
self._value = value
|
self._value = value
|
||||||
|
@ -153,12 +179,89 @@ class Attribute(BaseObject):
|
||||||
label = Property(str, getLabel, constant=True)
|
label = Property(str, getLabel, constant=True)
|
||||||
desc = Property(desc.Attribute, lambda self: self.attributeDesc, constant=True)
|
desc = Property(desc.Attribute, lambda self: self.attributeDesc, constant=True)
|
||||||
valueChanged = Signal()
|
valueChanged = Signal()
|
||||||
value = Property("QVariant", value.fget, value.fset, notify=valueChanged)
|
value = Property(Variant, _get_value, _set_value, notify=valueChanged)
|
||||||
isOutput = Property(bool, isOutput.fget, constant=True)
|
isOutput = Property(bool, isOutput.fget, constant=True)
|
||||||
isLinkChanged = Signal()
|
isLinkChanged = Signal()
|
||||||
isLink = Property(bool, isLink.fget, notify=isLinkChanged)
|
isLink = Property(bool, isLink.fget, notify=isLinkChanged)
|
||||||
|
|
||||||
|
|
||||||
|
class ListAttribute(Attribute):
|
||||||
|
|
||||||
|
def __init__(self, name, node, attributeDesc, parent=None):
|
||||||
|
super(ListAttribute, self).__init__(name, node, attributeDesc, parent)
|
||||||
|
self._value = ListModel(parent=self)
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return self._value.at(item)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._value)
|
||||||
|
|
||||||
|
def _set_value(self, value):
|
||||||
|
self._value.clear()
|
||||||
|
self.extend(value)
|
||||||
|
|
||||||
|
def append(self, value):
|
||||||
|
self.extend([value])
|
||||||
|
|
||||||
|
def insert(self, value, index):
|
||||||
|
attr = attribute_factory(self.attributeDesc.elementDesc, "", value, self.node, self)
|
||||||
|
self._value.insert(index, [attr])
|
||||||
|
|
||||||
|
def index(self, item):
|
||||||
|
return self._value.indexOf(item)
|
||||||
|
|
||||||
|
def extend(self, values):
|
||||||
|
childAttributes = []
|
||||||
|
for value in values:
|
||||||
|
attr = attribute_factory(self.attributeDesc.elementDesc, "", value, self.node, parent=self)
|
||||||
|
childAttributes.append(attr)
|
||||||
|
self._value.extend(childAttributes)
|
||||||
|
|
||||||
|
def remove(self, index):
|
||||||
|
self._value.removeAt(index)
|
||||||
|
|
||||||
|
def getExportValue(self):
|
||||||
|
return [attr.getExportValue() for attr in self._value]
|
||||||
|
|
||||||
|
# Override value property setter
|
||||||
|
value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged)
|
||||||
|
|
||||||
|
|
||||||
|
class GroupAttribute(Attribute):
|
||||||
|
|
||||||
|
def __init__(self, name, node, attributeDesc, parent=None):
|
||||||
|
super(GroupAttribute, self).__init__(name, node, attributeDesc, parent)
|
||||||
|
self._value = DictModel(keyAttrName='name', parent=self)
|
||||||
|
|
||||||
|
subAttributes = []
|
||||||
|
for name, subAttrDesc in self.attributeDesc.groupDesc.items():
|
||||||
|
childAttr = attribute_factory(subAttrDesc, name, None, self.node, parent=self)
|
||||||
|
subAttributes.append(childAttr)
|
||||||
|
|
||||||
|
self._value.reset(subAttributes)
|
||||||
|
|
||||||
|
def __getattr__(self, key):
|
||||||
|
try:
|
||||||
|
return super(GroupAttribute, self).__getattr__(key)
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
return self._value.get(key)
|
||||||
|
except KeyError:
|
||||||
|
raise AttributeError(key)
|
||||||
|
|
||||||
|
def _set_value(self, exportedValue):
|
||||||
|
# set individual child attribute values
|
||||||
|
for key, value in exportedValue.items():
|
||||||
|
self._value.get(key).value = value
|
||||||
|
|
||||||
|
def getExportValue(self):
|
||||||
|
return {key: attr.getExportValue() for key, attr in self._value.objects.items()}
|
||||||
|
|
||||||
|
# Override value property
|
||||||
|
value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged)
|
||||||
|
|
||||||
|
|
||||||
class Edge(BaseObject):
|
class Edge(BaseObject):
|
||||||
|
|
||||||
def __init__(self, src, dst, parent=None):
|
def __init__(self, src, dst, parent=None):
|
||||||
|
@ -217,6 +320,10 @@ class Node(BaseObject):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Regexp handling complex attribute names with recursive understanding of Lists and Groups
|
||||||
|
# i.e: a.b, a[0], a[0].b.c[1]
|
||||||
|
attributeRE = re.compile(r'\.?(?P<name>\w+)(?:\[(?P<index>\d+)\])?')
|
||||||
|
|
||||||
def __init__(self, nodeDesc, parent=None, **kwargs):
|
def __init__(self, nodeDesc, parent=None, **kwargs):
|
||||||
super(Node, self).__init__(parent)
|
super(Node, self).__init__(parent)
|
||||||
self._name = None # type: str
|
self._name = None # type: str
|
||||||
|
@ -227,7 +334,7 @@ class Node(BaseObject):
|
||||||
self.attributesPerUid = defaultdict(set)
|
self.attributesPerUid = defaultdict(set)
|
||||||
self._initFromDesc()
|
self._initFromDesc()
|
||||||
for k, v in kwargs.items():
|
for k, v in kwargs.items():
|
||||||
self.attribute(k)._value = v
|
self.attribute(k).value = v
|
||||||
self.status = StatusData(self.name, self.nodeType())
|
self.status = StatusData(self.name, self.nodeType())
|
||||||
self.statistics = stats.Statistics()
|
self.statistics = stats.Statistics()
|
||||||
self._subprocess = None
|
self._subprocess = None
|
||||||
|
@ -248,20 +355,36 @@ class Node(BaseObject):
|
||||||
|
|
||||||
@Slot(str, result=Attribute)
|
@Slot(str, result=Attribute)
|
||||||
def attribute(self, name):
|
def attribute(self, name):
|
||||||
return self._attributes.get(name)
|
att = None
|
||||||
|
# Complex name indicating group or list attribute
|
||||||
|
if '[' in name or '.' in name:
|
||||||
|
p = self.attributeRE.findall(name)
|
||||||
|
|
||||||
|
for n, idx in p:
|
||||||
|
# first step: get root attribute
|
||||||
|
if att is None:
|
||||||
|
att = self._attributes.get(n)
|
||||||
|
else:
|
||||||
|
# get child Attribute in Group
|
||||||
|
assert isinstance(att, GroupAttribute)
|
||||||
|
att = att.value.get(n)
|
||||||
|
if idx != '':
|
||||||
|
# get child Attribute in List
|
||||||
|
assert isinstance(att, ListAttribute)
|
||||||
|
att = att.value.at(int(idx))
|
||||||
|
else:
|
||||||
|
att = self._attributes.get(name)
|
||||||
|
return att
|
||||||
|
|
||||||
def getAttributes(self):
|
def getAttributes(self):
|
||||||
return self._attributes
|
return self._attributes
|
||||||
|
|
||||||
def _initFromDesc(self):
|
def _initFromDesc(self):
|
||||||
# Init from class members
|
# Init from class and instance members
|
||||||
for name, desc in self.nodeDesc.__class__.__dict__.items():
|
for name, desc in vars(self.nodeDesc.__class__).items() + vars(self.nodeDesc).items():
|
||||||
if issubclass(desc.__class__, pg.desc.Attribute):
|
if issubclass(desc.__class__, pg.desc.Attribute):
|
||||||
self._attributes.add(Attribute(name, self, desc))
|
self._attributes.add(attribute_factory(desc, name, None, self))
|
||||||
# Init from instance members
|
|
||||||
for name, desc in self.nodeDesc.__dict__.items():
|
|
||||||
if issubclass(desc.__class__, pg.desc.Attribute):
|
|
||||||
self._attributes.add(Attribute(name, self, desc))
|
|
||||||
# List attributes per uid
|
# List attributes per uid
|
||||||
for attr in self._attributes:
|
for attr in self._attributes:
|
||||||
for uidIndex in attr.attributeDesc.uid:
|
for uidIndex in attr.attributeDesc.uid:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue