Skip to content

Commit

Permalink
Add colour.utilities.NodePassthrough, colour.utilities.NodeLog, `…
Browse files Browse the repository at this point in the history
…colour.utilities.NodeSleep` and `colour.utilities.NodeSetGraphOutputPort` node classes.
  • Loading branch information
KelSolaar committed Dec 31, 2024
1 parent 9925c3e commit 759314a
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 2 deletions.
8 changes: 8 additions & 0 deletions colour/utilities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@
For,
ParallelForThread,
ParallelForMultiprocess,
NodePassthrough,
NodeLog,
NodeSleep,
NodeSetGraphOutputPort,
)
from colour.utilities.deprecation import ModuleAPI, build_API_changes
from colour.utilities.documentation import is_documentation_building
Expand Down Expand Up @@ -297,6 +301,10 @@
"For",
"ParallelForThread",
"ParallelForMultiprocess",
"NodePassthrough",
"NodeLog",
"NodeSleep",
"NodeSetGraphOutputPort",
]


Expand Down
131 changes: 130 additions & 1 deletion colour/utilities/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
parallel in the node-graph using threads.
- :class:`colour.utilities.ParallelForMultiprocess`: A node performing for
loops in parallel in the node-graph using multiprocessing.
- :class:`colour.utilities.NodePassthrough`: A node passing the input data
through.
- :class:`colour.utilities.NodeLog`: A node logging the input data.
- :class:`colour.utilities.NodeSleep`: A node sleeping for given duration in
seconds.
"""

from __future__ import annotations
Expand All @@ -34,6 +39,7 @@
import multiprocessing
import os
import threading
import time
import typing

if typing.TYPE_CHECKING:
Expand Down Expand Up @@ -73,6 +79,10 @@
"ParallelForThread",
"ProcessPoolExecutorManager",
"ParallelForMultiprocess",
"NodePassthrough",
"NodeLog",
"NodeSleep",
"NodeSetGraphOutputPort",
]


Expand Down Expand Up @@ -873,7 +883,10 @@ def connect(self, port: Port) -> None:

attest(isinstance(port, Port), f'"{port}" is not a "Port" instance!')

self.log(f'Connecting "{self.name}" to "{port.name}".', "debug")
self.log(
f'Connecting "{self.node}.{self.name}" to "{port.node}.{port.name}".',
"debug",
)

self.connections[port] = None
port.connections[self] = None
Expand Down Expand Up @@ -2514,3 +2527,119 @@ def process(self) -> None:
execution_output_node.process()

self.dirty = False


class NodePassthrough(PortNode):
"""
Pass the input data through.
Methods
-------
- :meth:`~colour.utilities.NodePassthrough.__init__`
- :meth:`~colour.utilities.NodePassthrough.process`
"""

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)

self.description = "Pass the input data through"

self.add_input_port("input")
self.add_output_port("output")

@notify_process_state
def process(self, **kwargs: Any) -> None: # noqa: ARG002
"""
Process the node.
"""

self.set_output("output", self.get_input("input"))

self.dirty = False


class NodeLog(ExecutionNode):
"""
Log the input data.
Methods
-------
- :meth:`~colour.utilities.NodeLog.__init__`
- :meth:`~colour.utilities.NodeLog.process`
"""

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)

self.description = "Log the input data"

self.add_input_port("input")
self.add_input_port("verbosity", "info")

@notify_process_state
def process(self, **kwargs: Any) -> None: # noqa: ARG002
"""
Process the node.
"""

self.log(self.get_input("input"), self.get_input("verbosity"))

self.dirty = False


class NodeSleep(ExecutionNode):
"""
Sleep for given duration in seconds.
Methods
-------
- :meth:`~colour.utilities.NodeLog.__init__`
- :meth:`~colour.utilities.NodeLog.process`
"""

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)

self.description = "Sleep for given duration in seconds"

self.add_input_port("duration", 0)

@notify_process_state
def process(self, **kwargs: Any) -> None: # noqa: ARG002
"""
Process the node.
"""

time.sleep(self.get_input("duration"))

self.dirty = False


class NodeSetGraphOutputPort(ExecutionNode):
"""
Set the parent graph given output with given value.
Methods
-------
- :meth:`~colour.utilities.NodeSetGraphOutputPort.__init__`
- :meth:`~colour.utilities.NodeSetGraphOutputPort.process`
"""

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)

self.description = "Set the parent graph given output with given value"

self.add_input_port("output")
self.add_input_port("value")

@notify_process_state
def process(self, **kwargs: Any) -> None: # noqa: ARG002
"""
Process the node.
"""

if self.parent is not None:
self.parent.set_output(self.get_input("output"), self.get_input("value"))

self.dirty = False
78 changes: 77 additions & 1 deletion colour/utilities/tests/test_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import re
import time
import typing

import numpy as np
Expand All @@ -13,18 +14,22 @@
from colour.utilities import (
ExecutionNode,
For,
NodeLog,
NodePassthrough,
NodeSetGraphOutputPort,
NodeSleep,
ParallelForMultiprocess,
ParallelForThread,
Port,
PortGraph,
PortNode,
TreeNode,
is_pydot_installed,
notify_process_state,
)
from colour.utilities.network import (
ProcessPoolExecutorManager,
ThreadPoolExecutorManager,
notify_process_state,
)

__author__ = "Colour Developers"
Expand All @@ -44,6 +49,10 @@
"TestParallelForThread",
"TestProcessPoolExecutorManager",
"TestParallelForMultiProcess",
"TestNodePassthrough",
"TestNodeLog",
"TestNodeSleep",
"TestNodeSetGraphOutputPort",
]


Expand Down Expand Up @@ -1208,3 +1217,70 @@ def test_ParallelForMultiProcess(self) -> None:
loop.process()

assert sum_array.get_output("summation") == 140


class TestNodePassthrough:
"""
Define :class:`colour.utilities.network.NodePassthrough` class unit tests
methods.
"""

def test_NodePassthrough(self) -> None:
"""Test the :class:`colour.utilities.network.NodePassthrough` class."""

node = NodePassthrough()
node.set_input("input", 1)
node.process()

assert node.get_output("output") == 1


class TestNodeLog:
"""
Define :class:`colour.utilities.network.NodeLog` class unit tests
methods.
"""

def test_NodeLog(self) -> None:
"""Test the :class:`colour.utilities.network.NodeLog` class."""

node = NodeLog()
node.set_input("input", "Foo")
node.process()


class TestNodeSleep:
"""
Define :class:`colour.utilities.network.NodeSleep` class unit tests
methods.
"""

def test_NodeSleep(self) -> None:
"""Test the :class:`colour.utilities.network.NodeSleep` class."""

node = NodeSleep()
node.set_input("duration", 1)
then = time.time()
node.process()

assert 1.25 > time.time() - then > 0.75


class TestNodeSetGraphOutputPort:
"""
Define :class:`colour.utilities.network.NodeSetGraphOutputPort` class unit tests
methods.
"""

def test_NodeSetGraphOutputPort(self) -> None:
"""Test the :class:`colour.utilities.network.NodeSetGraphOutputPort` class."""

graph = PortGraph()
graph.add_output_port("result")
node = NodeSetGraphOutputPort()
node.set_input("output", "result")
node.set_input("value", 1)
graph.add_node(node)
graph.process()

assert graph.get_output("result") == 1
4 changes: 4 additions & 0 deletions docs/colour.utilities.rst
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ Network
ParallelForThread
ProcessPoolExecutorManager
ParallelForMultiprocess
NodePassthrough
NodeLog
NodeSleep
NodeSetGraphOutput

.. currentmodule:: colour.utilities

Expand Down

0 comments on commit 759314a

Please sign in to comment.