Centralize the handling of link assigment by value in a dedicated
private method.
Store link assignment by value in a separate member variable
`_linkExpression`, to avoid manipulating a internal `_value` that
can represent different concepts (value VS serialized edge expression).
The desc.Node.onCreated callback is a hook in the Node API for developers to
write custom behavior on a node first initialization.
By being called in the core.Node constructor, this was triggered in several situations
that don't match this idea and with unpredictable side effects (graph loading, node re-creation on undo...).
* Make `onNodeCreated` callback an explicit method on desc.Node.
* Remove the call to node descriptor's `onNodeCreated` callback outside core.Node constructor.
* Trigger this callback on explicit node creation (adding new node to graph, init a graph from a template).
* Deserialization: Replace the logic that defaulted the node type version to "0.0" when unspecified,
and assume that unspecified version on a node is targetting current node type version.
* Serialization: Only serialize node type versions for which a version info is available.
* Test suites:
* Add helper context manager to manually override the version of a given node type.
* Add new unit tests to cover version conflicts handling is various scenarios.
At the end of the deserialization process, solve node uid conflicts iteratively by node depths,
and only replace the conflicting nodes with a CompatibilityNode.
Add new test suite for testing uid conflict handling.
Add a new method to create a copy of a graph instance, relying on
chaining serialization and deserialization operations.
Add test suite to validate its behavior, and the underlying serialization processes.
Re-implement node pasting by relying on the graph partial serializer,
to serialize only the subset of selected nodes.
On pasting, use standard graph deserialization and import the content
of the serialized graph in the active graph instance.
Simplify the positioning of pasted nodes to only consider mouse position
or center of the graph, which works well for the major variety of use-cases.
Compute the offset to apply to imported nodes by using the de-serialized
graph content's bounding box.
Only perform uid check when we have both a serialized and a computed
UID.
If the node has not been serialized with a UID, it means that it does not
expect to match a specific value on deserialization.
Add a new serializer class to manage partial graph serialization logic,
ensuring to remove link expressions on attributes refering to nodes
that are not in the subset of nodes to serialize.
Move the serialization logic to dedicated serializer classes.
Implement both `GraphSerializer` and `TemplateGraphSerializer`
to cover for the existing serialization use-cases.
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.
Extract the logic of importing the content of a graph within a graph instance from
the graph loading logic.
Add `Graph.importGraphContent` and `Graph.importGraphContentFromFile`
methods.
Use the deserialization API to load the content in another temporary graph instance,
to handle the renaming of nodes using the Graph API, rather than manipulating
entries in a raw dictionnary.
* API
Instead of having a single `load` function that exposes in its API
some elements only applicable to initializing a graph from a templates,
split it into 2 distinct functions: `load` and `initFromTemplate`.
Apply those changes to users of the API (UI, CLI), and simplify Graph
wrapper classes to better align with those concepts.
* Deserialization
Reduce the cognitive complexity of the deserizalization process
by splitting it into more atomic functions, while maintaining the
current behavior.
The 'isSaving' flag is a way to identify if the project is currently being saved and serves as a way to correctly distinguish whether the current filepath change is due to a save or a new scene or a load operation
Provide a way to control how to handle node compatibility issues
when loading a Graph with the `strictCompatibility` parameter.
Introduce a new error type, GraphCompatibilityError, to be raised
when loading a Graph with compatibility issues with strictCompatibility enabled.
The file version is updated and support for files with an older version
is added: upon detecting that the file version is old, the old UID
keys will be detected and reformatted with new ones so the file can
be properly loaded.
The UID system based on a UID index is removed and replaced by a single
UID per node.
Attributes will be included in the UID computation if the `invalidate`
is set to `True` in their description. This replaces the `uid=[]` /
`uid=[0]` element of the description.
If the edges of a node to submit include an `InputNode` (which cannot
be computed), then that node should be excluded from the list of edges
to process as if that node had already been computed.
This allows to submit any type of graph involving `InputNode` to the farm.
The `selectedViewpoint` property will store the attribute corresponding to
the actively selected viewpoint, if it exists. Otherwise, it will be set
to None.
The behaviour regarding `ListAttributes` was different depending on
whether an edge or a node was removed:
- if an edge was removed, the `ListAttribute` that was the destination
of that edge had its corresponding element completely removed;
- if a node was removed, the `ListAttribute` that was the destination
of one of the node's edges had its corresponding element reset, but not
removed.
With this behaviour, a user had different UIDs depending on whether
a single edge or the whole node had been removed where the UID should
always be identical.
Up until this commit, compatibility nodes (which necessarily had a version
or description issue) were ignored during the evaluation of UID conflicts,
as they had no UID.
This however created a bug, where already existing compatibility nodes
with inputs from nodes that triggered UID conflicts were losing their
input connections: when the node with the UID conflict was replaced with
a new compatibility node (with a UID conflict issue), the link was broken
and could not be resolved anymore as it lost any mention of the input
node's name. This was also valid for nodes without any compatibility issue
which had UID conflicted-nodes as their inputs.
Processing all the nodes in addition to those with a UID conflict issue
prevents this from happening: edges are correctly preserved.
This also fixes an issue that occurred when opening a project file that
contained nodes whose type was not recognized. Instead of raising an
"unknown node type" compatibility issue, "attribute is already connected"
errors were raised for the unrecognized nodes.
When loading the graph, once all the nodes have been created and the
links resolved, the computed nodes' UID can be compared with those
stored in the graph.
If a mismatch is detected, the node that presents the UID conflict is
removed from the graph and replaced with a CompatibilityNode, set with
`UidConflict`.
Nodes that come from templates are ignored as no UID is stored in
templates. Similarly, nodes that are already Compatibility nodes are left
out as they do not have a UID.