mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-06-03 03:11:56 +02:00
[core] Introducing new graphIO module
Move Graph.IO internal class to its own module, and rename it to `GraphIO`. This avoid nested classes within the core Graph class, and starts decoupling the management of graph's IO from the logic of the graph itself.
This commit is contained in:
parent
3064cb9b35
commit
a665200c38
4 changed files with 76 additions and 63 deletions
|
@ -17,6 +17,7 @@ from meshroom.common import BaseObject, DictModel, Slot, Signal, Property
|
||||||
from meshroom.core import Version
|
from meshroom.core import Version
|
||||||
from meshroom.core.attribute import Attribute, ListAttribute, GroupAttribute
|
from meshroom.core.attribute import Attribute, ListAttribute, GroupAttribute
|
||||||
from meshroom.core.exception import GraphCompatibilityError, StopGraphVisit, StopBranchVisit
|
from meshroom.core.exception import GraphCompatibilityError, StopGraphVisit, StopBranchVisit
|
||||||
|
from meshroom.core.graphIO import GraphIO
|
||||||
from meshroom.core.node import Status, Node, CompatibilityNode
|
from meshroom.core.node import Status, Node, CompatibilityNode
|
||||||
from meshroom.core.nodeFactory import nodeFactory
|
from meshroom.core.nodeFactory import nodeFactory
|
||||||
from meshroom.core.typing import PathLike
|
from meshroom.core.typing import PathLike
|
||||||
|
@ -183,52 +184,6 @@ class Graph(BaseObject):
|
||||||
"""
|
"""
|
||||||
_cacheDir = ""
|
_cacheDir = ""
|
||||||
|
|
||||||
class IO(object):
|
|
||||||
""" Centralize Graph file keys and IO version. """
|
|
||||||
__version__ = "2.0"
|
|
||||||
|
|
||||||
class Keys(object):
|
|
||||||
""" File Keys. """
|
|
||||||
# Doesn't inherit enum to simplify usage (Graph.IO.Keys.XX, without .value)
|
|
||||||
Header = "header"
|
|
||||||
NodesVersions = "nodesVersions"
|
|
||||||
ReleaseVersion = "releaseVersion"
|
|
||||||
FileVersion = "fileVersion"
|
|
||||||
Graph = "graph"
|
|
||||||
|
|
||||||
class Features(Enum):
|
|
||||||
""" File Features. """
|
|
||||||
Graph = "graph"
|
|
||||||
Header = "header"
|
|
||||||
NodesVersions = "nodesVersions"
|
|
||||||
PrecomputedOutputs = "precomputedOutputs"
|
|
||||||
NodesPositions = "nodesPositions"
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def getFeaturesForVersion(fileVersion):
|
|
||||||
""" Return the list of supported features based on a file version.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
fileVersion (str, Version): the file version
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
tuple of Graph.IO.Features: the list of supported features
|
|
||||||
"""
|
|
||||||
if isinstance(fileVersion, str):
|
|
||||||
fileVersion = Version(fileVersion)
|
|
||||||
|
|
||||||
features = [Graph.IO.Features.Graph]
|
|
||||||
if fileVersion >= Version("1.0"):
|
|
||||||
features += [Graph.IO.Features.Header,
|
|
||||||
Graph.IO.Features.NodesVersions,
|
|
||||||
Graph.IO.Features.PrecomputedOutputs,
|
|
||||||
]
|
|
||||||
|
|
||||||
if fileVersion >= Version("1.1"):
|
|
||||||
features += [Graph.IO.Features.NodesPositions]
|
|
||||||
|
|
||||||
return tuple(features)
|
|
||||||
|
|
||||||
def __init__(self, name, parent=None):
|
def __init__(self, name, parent=None):
|
||||||
super(Graph, self).__init__(parent)
|
super(Graph, self).__init__(parent)
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -265,7 +220,7 @@ class Graph(BaseObject):
|
||||||
@property
|
@property
|
||||||
def fileFeatures(self):
|
def fileFeatures(self):
|
||||||
""" Get loaded file supported features based on its version. """
|
""" Get loaded file supported features based on its version. """
|
||||||
return Graph.IO.getFeaturesForVersion(self.header.get(Graph.IO.Keys.FileVersion, "0.0"))
|
return GraphIO.getFeaturesForVersion(self.header.get(GraphIO.Keys.FileVersion, "0.0"))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def isLoading(self):
|
def isLoading(self):
|
||||||
|
@ -321,8 +276,8 @@ class Graph(BaseObject):
|
||||||
graphData: The serialized Graph.
|
graphData: The serialized Graph.
|
||||||
"""
|
"""
|
||||||
self.clear()
|
self.clear()
|
||||||
self.header = graphData.get(Graph.IO.Keys.Header, {})
|
self.header = graphData.get(GraphIO.Keys.Header, {})
|
||||||
fileVersion = Version(self.header.get(Graph.IO.Keys.FileVersion, "0.0"))
|
fileVersion = Version(self.header.get(GraphIO.Keys.FileVersion, "0.0"))
|
||||||
graphContent = self._normalizeGraphContent(graphData, fileVersion)
|
graphContent = self._normalizeGraphContent(graphData, fileVersion)
|
||||||
isTemplate = self.header.get("template", False)
|
isTemplate = self.header.get("template", False)
|
||||||
|
|
||||||
|
@ -355,7 +310,7 @@ class Graph(BaseObject):
|
||||||
logging.warning(e)
|
logging.warning(e)
|
||||||
|
|
||||||
def _normalizeGraphContent(self, graphData: dict, fileVersion: Version) -> dict:
|
def _normalizeGraphContent(self, graphData: dict, fileVersion: Version) -> dict:
|
||||||
graphContent = graphData.get(Graph.IO.Keys.Graph, graphData)
|
graphContent = graphData.get(GraphIO.Keys.Graph, graphData)
|
||||||
|
|
||||||
if fileVersion < Version("2.0"):
|
if fileVersion < Version("2.0"):
|
||||||
# For internal folders, all "{uid0}" keys should be replaced with "{uid}"
|
# For internal folders, all "{uid0}" keys should be replaced with "{uid}"
|
||||||
|
@ -388,7 +343,7 @@ class Graph(BaseObject):
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def _getNodeTypeVersionFromHeader(self, nodeType: str, default: Optional[str] = None) -> Optional[str]:
|
def _getNodeTypeVersionFromHeader(self, nodeType: str, default: Optional[str] = None) -> Optional[str]:
|
||||||
nodeVersions = self.header.get(Graph.IO.Keys.NodesVersions, {})
|
nodeVersions = self.header.get(GraphIO.Keys.NodesVersions, {})
|
||||||
return nodeVersions.get(nodeType, default)
|
return nodeVersions.get(nodeType, default)
|
||||||
|
|
||||||
def _evaluateUidConflicts(self, data):
|
def _evaluateUidConflicts(self, data):
|
||||||
|
@ -1453,8 +1408,8 @@ class Graph(BaseObject):
|
||||||
if not path:
|
if not path:
|
||||||
raise ValueError("filepath must be specified for unsaved files.")
|
raise ValueError("filepath must be specified for unsaved files.")
|
||||||
|
|
||||||
self.header[Graph.IO.Keys.ReleaseVersion] = meshroom.__version__
|
self.header[GraphIO.Keys.ReleaseVersion] = meshroom.__version__
|
||||||
self.header[Graph.IO.Keys.FileVersion] = Graph.IO.__version__
|
self.header[GraphIO.Keys.FileVersion] = GraphIO.__version__
|
||||||
|
|
||||||
# Store versions of node types present in the graph (excluding CompatibilityNode instances)
|
# Store versions of node types present in the graph (excluding CompatibilityNode instances)
|
||||||
# and remove duplicates
|
# and remove duplicates
|
||||||
|
@ -1467,19 +1422,19 @@ class Graph(BaseObject):
|
||||||
# Sort them by name (to avoid random order changing from one save to another)
|
# Sort them by name (to avoid random order changing from one save to another)
|
||||||
nodesVersions = dict(sorted(nodesVersions.items()))
|
nodesVersions = dict(sorted(nodesVersions.items()))
|
||||||
# Add it the header
|
# Add it the header
|
||||||
self.header[Graph.IO.Keys.NodesVersions] = nodesVersions
|
self.header[GraphIO.Keys.NodesVersions] = nodesVersions
|
||||||
self.header["template"] = template
|
self.header["template"] = template
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
if template:
|
if template:
|
||||||
data = {
|
data = {
|
||||||
Graph.IO.Keys.Header: self.header,
|
GraphIO.Keys.Header: self.header,
|
||||||
Graph.IO.Keys.Graph: self.getNonDefaultInputAttributes()
|
GraphIO.Keys.Graph: self.getNonDefaultInputAttributes()
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
data = {
|
data = {
|
||||||
Graph.IO.Keys.Header: self.header,
|
GraphIO.Keys.Header: self.header,
|
||||||
Graph.IO.Keys.Graph: self.toDict()
|
GraphIO.Keys.Graph: self.toDict()
|
||||||
}
|
}
|
||||||
|
|
||||||
with open(path, 'w') as jsonFile:
|
with open(path, 'w') as jsonFile:
|
||||||
|
@ -1734,7 +1689,7 @@ class Graph(BaseObject):
|
||||||
filepathChanged = Signal()
|
filepathChanged = Signal()
|
||||||
filepath = Property(str, lambda self: self._filepath, notify=filepathChanged)
|
filepath = Property(str, lambda self: self._filepath, notify=filepathChanged)
|
||||||
isSaving = Property(bool, isSaving.fget, constant=True)
|
isSaving = Property(bool, isSaving.fget, constant=True)
|
||||||
fileReleaseVersion = Property(str, lambda self: self.header.get(Graph.IO.Keys.ReleaseVersion, "0.0"),
|
fileReleaseVersion = Property(str, lambda self: self.header.get(GraphIO.Keys.ReleaseVersion, "0.0"),
|
||||||
notify=filepathChanged)
|
notify=filepathChanged)
|
||||||
fileDateVersion = Property(float, fileDateVersion.fget, fileDateVersion.fset, notify=filepathChanged)
|
fileDateVersion = Property(float, fileDateVersion.fget, fileDateVersion.fset, notify=filepathChanged)
|
||||||
cacheDirChanged = Signal()
|
cacheDirChanged = Signal()
|
||||||
|
|
56
meshroom/core/graphIO.py
Normal file
56
meshroom/core/graphIO.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from meshroom.core import Version
|
||||||
|
|
||||||
|
|
||||||
|
class GraphIO:
|
||||||
|
"""Centralize Graph file keys and IO version."""
|
||||||
|
|
||||||
|
__version__ = "2.0"
|
||||||
|
|
||||||
|
class Keys(object):
|
||||||
|
"""File Keys."""
|
||||||
|
|
||||||
|
# Doesn't inherit enum to simplify usage (GraphIO.Keys.XX, without .value)
|
||||||
|
Header = "header"
|
||||||
|
NodesVersions = "nodesVersions"
|
||||||
|
ReleaseVersion = "releaseVersion"
|
||||||
|
FileVersion = "fileVersion"
|
||||||
|
Graph = "graph"
|
||||||
|
|
||||||
|
class Features(Enum):
|
||||||
|
"""File Features."""
|
||||||
|
|
||||||
|
Graph = "graph"
|
||||||
|
Header = "header"
|
||||||
|
NodesVersions = "nodesVersions"
|
||||||
|
PrecomputedOutputs = "precomputedOutputs"
|
||||||
|
NodesPositions = "nodesPositions"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getFeaturesForVersion(fileVersion: Union[str, Version]) -> tuple["GraphIO.Features",...]:
|
||||||
|
"""Return the list of supported features based on a file version.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fileVersion (str, Version): the file version
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple of GraphIO.Features: the list of supported features
|
||||||
|
"""
|
||||||
|
if isinstance(fileVersion, str):
|
||||||
|
fileVersion = Version(fileVersion)
|
||||||
|
|
||||||
|
features = [GraphIO.Features.Graph]
|
||||||
|
if fileVersion >= Version("1.0"):
|
||||||
|
features += [
|
||||||
|
GraphIO.Features.Header,
|
||||||
|
GraphIO.Features.NodesVersions,
|
||||||
|
GraphIO.Features.PrecomputedOutputs,
|
||||||
|
]
|
||||||
|
|
||||||
|
if fileVersion >= Version("1.1"):
|
||||||
|
features += [GraphIO.Features.NodesPositions]
|
||||||
|
|
||||||
|
return tuple(features)
|
||||||
|
|
|
@ -25,6 +25,7 @@ from meshroom.core import sessionUid
|
||||||
from meshroom.common.qt import QObjectListModel
|
from meshroom.common.qt import QObjectListModel
|
||||||
from meshroom.core.attribute import Attribute, ListAttribute
|
from meshroom.core.attribute import Attribute, ListAttribute
|
||||||
from meshroom.core.graph import Graph, Edge
|
from meshroom.core.graph import Graph, Edge
|
||||||
|
from meshroom.core.graphIO import GraphIO
|
||||||
|
|
||||||
from meshroom.core.taskManager import TaskManager
|
from meshroom.core.taskManager import TaskManager
|
||||||
|
|
||||||
|
@ -396,7 +397,7 @@ class UIGraph(QObject):
|
||||||
self.updateChunks()
|
self.updateChunks()
|
||||||
|
|
||||||
# perform auto-layout if graph does not provide nodes positions
|
# perform auto-layout if graph does not provide nodes positions
|
||||||
if Graph.IO.Features.NodesPositions not in self._graph.fileFeatures:
|
if GraphIO.Features.NodesPositions not in self._graph.fileFeatures:
|
||||||
self._layout.reset()
|
self._layout.reset()
|
||||||
# clear undo-stack after layout
|
# clear undo-stack after layout
|
||||||
self._undoStack.clear()
|
self._undoStack.clear()
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
from meshroom.core.graph import Graph
|
from meshroom.core.graph import Graph
|
||||||
from meshroom.core import pipelineTemplates, Version
|
from meshroom.core import pipelineTemplates, Version
|
||||||
from meshroom.core.node import CompatibilityIssue, CompatibilityNode
|
from meshroom.core.node import CompatibilityIssue, CompatibilityNode
|
||||||
|
from meshroom.core.graphIO import GraphIO
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import meshroom
|
import meshroom
|
||||||
|
@ -24,13 +25,13 @@ def test_templateVersions():
|
||||||
with open(path) as jsonFile:
|
with open(path) as jsonFile:
|
||||||
fileData = json.load(jsonFile)
|
fileData = json.load(jsonFile)
|
||||||
|
|
||||||
graphData = fileData.get(Graph.IO.Keys.Graph, fileData)
|
graphData = fileData.get(GraphIO.Keys.Graph, fileData)
|
||||||
|
|
||||||
assert isinstance(graphData, dict)
|
assert isinstance(graphData, dict)
|
||||||
|
|
||||||
header = fileData.get(Graph.IO.Keys.Header, {})
|
header = fileData.get(GraphIO.Keys.Header, {})
|
||||||
assert header.get("template", False)
|
assert header.get("template", False)
|
||||||
nodesVersions = header.get(Graph.IO.Keys.NodesVersions, {})
|
nodesVersions = header.get(GraphIO.Keys.NodesVersions, {})
|
||||||
|
|
||||||
for _, nodeData in graphData.items():
|
for _, nodeData in graphData.items():
|
||||||
nodeType = nodeData["nodeType"]
|
nodeType = nodeData["nodeType"]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue