|
12 | 12 | from collections.abc import Iterable, Sequence |
13 | 13 | from string import Template |
14 | 14 | from meshroom.common import BaseObject, Property, Variant, Signal, ListModel, DictModel, Slot |
| 15 | +from meshroom.core.desc.validators import NotEmptyValidator |
15 | 16 | from meshroom.core import desc, hashValue |
16 | 17 | from meshroom.core.keyValues import KeyValues |
17 | 18 | from meshroom.core.exception import InvalidEdgeError |
@@ -84,6 +85,7 @@ def __init__(self, node, attributeDesc: desc.Attribute, isOutput: bool, root=Non |
84 | 85 | self._enabled: bool = True |
85 | 86 | self._depth: int = root.depth + 1 if root is not None else 0 |
86 | 87 | self._exposed: bool = root.exposed if root is not None else attributeDesc.exposed |
| 88 | + self._description: str = attributeDesc.description |
87 | 89 | self._invalidate = False if self._isOutput else attributeDesc.invalidate |
88 | 90 | self._invalidationValue = "" # invalidation value for output attributes |
89 | 91 | self._value = None |
@@ -235,6 +237,15 @@ def _setValue(self, value): |
235 | 237 | self.requestNodeUpdate() |
236 | 238 | self.valueChanged.emit() |
237 | 239 |
|
| 240 | + def _get_description(self): |
| 241 | + return self._description |
| 242 | + |
| 243 | + def _set_description(self, desc): |
| 244 | + if self._description == desc: |
| 245 | + return |
| 246 | + self._description = desc |
| 247 | + self.descriptionChanged.emit() |
| 248 | + |
238 | 249 | def _getKeyValues(self): |
239 | 250 | """ |
240 | 251 | Return the per-key values object of the attribute or of the linked attribute. |
@@ -401,21 +412,6 @@ def _isDefault(self): |
401 | 412 | else: |
402 | 413 | return self._getValue() == self.getDefaultValue() |
403 | 414 |
|
404 | | - def _isValid(self): |
405 | | - """ |
406 | | - Check attribute description validValue: |
407 | | - - If it is a function, execute it and return the result |
408 | | - - Otherwise, simply return true |
409 | | - """ |
410 | | - if callable(self._desc.validValue): |
411 | | - try: |
412 | | - return self._desc.validValue(self.node) |
413 | | - except Exception as exc: |
414 | | - if not self.node.isCompatibilityNode: |
415 | | - logging.warning(f"Failed to evaluate 'isValid' (node lambda) for attribute '{self.fullName}': {exc}") |
416 | | - return True |
417 | | - return True |
418 | | - |
419 | 415 | def _is2dDisplayable(self) -> bool: |
420 | 416 | """ |
421 | 417 | Return True if the current attribute is considered as a displayable 2D file. |
@@ -487,6 +483,43 @@ def updateInternals(self): |
487 | 483 | # Emit if the enable status has changed |
488 | 484 | self._setEnabled(self._getEnabled()) |
489 | 485 |
|
| 486 | + def getErrorMessages(self) -> list[str]: |
| 487 | + """ Execute the validators and aggregate the eventual error messages""" |
| 488 | + |
| 489 | + result = [] |
| 490 | + |
| 491 | + for validator in self.desc.validators: |
| 492 | + isValid, errorMessages = validator(self.node, self) |
| 493 | + |
| 494 | + if isValid: |
| 495 | + continue |
| 496 | + |
| 497 | + for errorMessage in errorMessages: |
| 498 | + result.append(errorMessage) |
| 499 | + |
| 500 | + return result |
| 501 | + |
| 502 | + def _isValid(self) -> bool: |
| 503 | + """ Check the validation and return False if any validator return (False, erorrs) |
| 504 | + """ |
| 505 | + |
| 506 | + for validator in self.desc.validators: |
| 507 | + isValid, _ = validator(self.node, self) |
| 508 | + |
| 509 | + if not isValid: |
| 510 | + return False |
| 511 | + |
| 512 | + return True |
| 513 | + |
| 514 | + def _isMandatory(self) -> bool: |
| 515 | + """ An attribute is considered as mandatory it contain a NotEmptyValidator """ |
| 516 | + |
| 517 | + for validator in self.desc.validators: |
| 518 | + if isinstance(validator, NotEmptyValidator): |
| 519 | + return True |
| 520 | + |
| 521 | + return False |
| 522 | + |
490 | 523 | def _getEnabled(self) -> bool: |
491 | 524 | if callable(self._desc.enabled): |
492 | 525 | try: |
@@ -742,6 +775,9 @@ def validateIncomingConnection(self, connectingAttribute: Attribute) -> bool: |
742 | 775 |
|
743 | 776 | expressionApplied = Signal() |
744 | 777 |
|
| 778 | + errorMessageChanged = Signal() |
| 779 | + errorMessages = Property(Variant, lambda self: self.getErrorMessages(), notify=errorMessageChanged) |
| 780 | + isMandatory = Property(bool, _isMandatory, constant=True ) |
745 | 781 |
|
746 | 782 | def raiseIfLink(func): |
747 | 783 | """ |
|
0 commit comments