nodebpy 0.16.0__tar.gz → 0.18.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nodebpy-0.16.0 → nodebpy-0.18.0}/PKG-INFO +2 -2
- {nodebpy-0.16.0 → nodebpy-0.18.0}/README.md +1 -1
- {nodebpy-0.16.0 → nodebpy-0.18.0}/pyproject.toml +4 -3
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/arrange.py +5 -1
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/builder/_utils.py +1 -1
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/builder/accessor.py +4 -2
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/builder/mixins.py +74 -44
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/builder/node.py +3 -3
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/builder/socket.py +674 -59
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/builder/tree.py +10 -7
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/diagram.py +4 -2
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/arrange/graph.py +3 -3
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/arrange/ordering.py +5 -5
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/arrange/ranking.py +2 -2
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/arrange/realize.py +2 -2
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/arrange/stacking.py +3 -3
- nodebpy-0.18.0/src/nodebpy/lib/nodearrange/arrange/structs.py +179 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/arrange/sugiyama.py +2 -1
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/arrange/x_coords.py +3 -3
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/arrange/y_coords.py +1 -1
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/color.py +6 -4
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/converter.py +16 -238
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/input.py +1 -1
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/interface.py +9 -3
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/manual.py +113 -5
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/output.py +0 -10
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/attribute.py +2 -3
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/converter.py +34 -12
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/geometry.py +25 -7
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/grid.py +31 -31
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/groups.py +53 -14
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/input.py +7 -5
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/interface.py +21 -5
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/manual.py +63 -44
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/utilities.py +1 -1
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/zone.py +8 -5
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/converter.py +1 -1
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/shader.py +2 -2
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/texture.py +4 -2
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/types.py +1 -1
- nodebpy-0.16.0/src/nodebpy/lib/nodearrange/arrange/structs.py +0 -139
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/builder/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/builder/_registry.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/config.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/lib/nodearrange/utils.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/__init__.py +1 -1
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/distort.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/filter.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/group.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/matte.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/compositor/vector.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/color.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/group.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/output.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/texture.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/geometry/vector.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/color.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/grid.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/group.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/input.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/manual.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/output.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/script.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.18.0}/src/nodebpy/nodes/shader/vector.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: nodebpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.0
|
|
4
4
|
Summary: Build nodes trees in Blender more elegantly with code
|
|
5
5
|
Author: Brady Johnston
|
|
6
6
|
Author-email: Brady Johnston <brady.johnston@me.com>
|
|
@@ -130,7 +130,7 @@ Some nodes are manually specified in the `src/nodebpy/nodes/geometry/manual.py`
|
|
|
130
130
|
Run the build & format script as such:
|
|
131
131
|
|
|
132
132
|
```bash
|
|
133
|
-
uv run generate.py && uvx ruff format && uvx ruff check --fix
|
|
133
|
+
uv run generate.py && uvx ruff format && uvx ruff check --fix && uvx ty check --fix src
|
|
134
134
|
```
|
|
135
135
|
|
|
136
136
|
## Other Projects
|
|
@@ -116,7 +116,7 @@ Some nodes are manually specified in the `src/nodebpy/nodes/geometry/manual.py`
|
|
|
116
116
|
Run the build & format script as such:
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
|
-
uv run generate.py && uvx ruff format && uvx ruff check --fix
|
|
119
|
+
uv run generate.py && uvx ruff format && uvx ruff check --fix && uvx ty check --fix src
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
## Other Projects
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "nodebpy"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.18.0"
|
|
4
4
|
description = "Build nodes trees in Blender more elegantly with code"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -28,7 +28,7 @@ build-backend = "uv_build"
|
|
|
28
28
|
dev = [
|
|
29
29
|
"ipython>=8.0.0",
|
|
30
30
|
"networkx>=3.6.1",
|
|
31
|
-
"fake-bpy-module>=
|
|
31
|
+
"fake-bpy-module>=20260501",
|
|
32
32
|
"jsondiff>=2.2.1",
|
|
33
33
|
"pytest>=9.0.2",
|
|
34
34
|
"pytest-cov>=7.0.0",
|
|
@@ -38,5 +38,6 @@ dev = [
|
|
|
38
38
|
"syrupy>=5.0.0",
|
|
39
39
|
"tree-clipper>=0.1.1",
|
|
40
40
|
"pytest-xdist>=3.8.0",
|
|
41
|
-
"griffe<2.0.0"
|
|
41
|
+
"griffe<2.0.0",
|
|
42
|
+
"ty>=0.0.35",
|
|
42
43
|
]
|
|
@@ -117,7 +117,7 @@ def calculate_node_dimensions(
|
|
|
117
117
|
inherited_ids = {
|
|
118
118
|
prop.identifier
|
|
119
119
|
for base in type(node).__bases__
|
|
120
|
-
for prop in base
|
|
120
|
+
for prop in getattr(base, "bl_rna").properties
|
|
121
121
|
}
|
|
122
122
|
node_property_count = sum(
|
|
123
123
|
1 for prop in node.bl_rna.properties if prop.identifier not in inherited_ids
|
|
@@ -143,6 +143,7 @@ def calculate_node_dimensions(
|
|
|
143
143
|
|
|
144
144
|
def _socket_index(socket: bpy.types.NodeSocket) -> int:
|
|
145
145
|
"""Return the index of a socket among its node's enabled sockets."""
|
|
146
|
+
assert socket.node is not None
|
|
146
147
|
collection = socket.node.inputs if not socket.is_output else socket.node.outputs
|
|
147
148
|
idx = 0
|
|
148
149
|
for s in collection:
|
|
@@ -208,6 +209,7 @@ def _reduce_crossings(
|
|
|
208
209
|
# on the target node (input side).
|
|
209
210
|
out_count = max(1, sum(1 for s in src.outputs if s.enabled))
|
|
210
211
|
in_count = max(1, sum(1 for s in dst.inputs if s.enabled))
|
|
212
|
+
assert link.from_socket is not None and link.to_socket is not None
|
|
211
213
|
src_frac = _socket_index(link.from_socket) / out_count
|
|
212
214
|
dst_frac = _socket_index(link.to_socket) / in_count
|
|
213
215
|
|
|
@@ -299,8 +301,10 @@ def position_reroutes(tree: bpy.types.NodeTree) -> None:
|
|
|
299
301
|
targets: list[bpy.types.Node] = []
|
|
300
302
|
for link in tree.links:
|
|
301
303
|
if link.to_node == node:
|
|
304
|
+
assert link.from_node is not None
|
|
302
305
|
sources.append(link.from_node)
|
|
303
306
|
if link.from_node == node:
|
|
307
|
+
assert link.to_node is not None
|
|
304
308
|
targets.append(link.to_node)
|
|
305
309
|
|
|
306
310
|
neighbours = sources + targets
|
|
@@ -63,7 +63,7 @@ def _resolve_promotion(
|
|
|
63
63
|
"""
|
|
64
64
|
other_type = getattr(other, "type", None)
|
|
65
65
|
self_prec = _TYPE_PRECEDENCE.get(self_socket.type, 1)
|
|
66
|
-
other_prec = _TYPE_PRECEDENCE.get(other_type, -1)
|
|
66
|
+
other_prec = _TYPE_PRECEDENCE.get(other_type, -1) if other_type is not None else -1
|
|
67
67
|
|
|
68
68
|
if other_prec > self_prec:
|
|
69
69
|
# Other side is dominant — swap so the linker wraps the vector/higher socket
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Literal, overload
|
|
3
|
+
from typing import TYPE_CHECKING, Iterator, Literal, overload
|
|
4
4
|
|
|
5
5
|
import bpy
|
|
6
6
|
from bpy.types import NodeSocket
|
|
@@ -103,10 +103,12 @@ class SocketAccessor:
|
|
|
103
103
|
def _node(self) -> bpy.types.Node:
|
|
104
104
|
"""The node this accessor is associated with."""
|
|
105
105
|
if isinstance(self._collection, list):
|
|
106
|
+
assert self._collection[0].node is not None
|
|
106
107
|
return self._collection[0].node
|
|
107
108
|
# bpy NodeInputs/NodeOutputs.id_data returns the NodeTree (top-level ID),
|
|
108
109
|
# not the Node. Retrieve the node via the first socket instead.
|
|
109
110
|
for s in self._collection:
|
|
111
|
+
assert s.node is not None
|
|
110
112
|
return s.node
|
|
111
113
|
return self._collection.data # empty collection fallback
|
|
112
114
|
|
|
@@ -200,7 +202,7 @@ class SocketAccessor:
|
|
|
200
202
|
def __len__(self) -> int:
|
|
201
203
|
return len(self._items())
|
|
202
204
|
|
|
203
|
-
def __iter__(self):
|
|
205
|
+
def __iter__(self) -> Iterator["Socket"]:
|
|
204
206
|
return iter(self._values())
|
|
205
207
|
|
|
206
208
|
def __getattr__(self, name: str) -> "Socket":
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from types import EllipsisType
|
|
4
|
-
from typing import TYPE_CHECKING, Any, TypeVar, overload
|
|
4
|
+
from typing import TYPE_CHECKING, Any, TypeVar, cast, overload
|
|
5
5
|
|
|
6
6
|
from bpy.types import NodeLink, NodeSocket
|
|
7
7
|
|
|
@@ -11,8 +11,8 @@ from ._utils import SocketError, _resolve_promotion, _SocketLike
|
|
|
11
11
|
_RShiftT = TypeVar("_RShiftT")
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
|
-
from ..nodes.geometry import Compare, Math, MultiplyMatrices, TransformPoint
|
|
15
14
|
from ..types import InputLinkable
|
|
15
|
+
from .accessor import SocketAccessor
|
|
16
16
|
from .node import BaseNode
|
|
17
17
|
from .socket import (
|
|
18
18
|
BooleanSocket,
|
|
@@ -35,75 +35,78 @@ class OperatorMixin:
|
|
|
35
35
|
|
|
36
36
|
__array_ufunc__ = None
|
|
37
37
|
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def _default_output_socket(self) -> "NodeSocket": ...
|
|
42
|
+
|
|
38
43
|
def _apply_math_operation(
|
|
39
44
|
self, other: Any, operation: str, reverse: bool = False
|
|
40
45
|
) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
41
46
|
socket, other, reverse = _resolve_promotion(
|
|
42
47
|
self._default_output_socket,
|
|
43
48
|
other,
|
|
44
|
-
reverse,
|
|
49
|
+
reverse,
|
|
45
50
|
)
|
|
46
51
|
return _get_socket_linker(socket)._dispatch_math(other, operation, reverse)
|
|
47
52
|
|
|
48
|
-
def __mul__(self, other: Any) -> "FloatSocket":
|
|
53
|
+
def __mul__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
49
54
|
return self._apply_math_operation(other, "multiply")
|
|
50
55
|
|
|
51
|
-
def __rmul__(self, other: Any) -> "FloatSocket":
|
|
56
|
+
def __rmul__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
52
57
|
return self._apply_math_operation(other, "multiply", reverse=True)
|
|
53
58
|
|
|
54
|
-
def __truediv__(self, other: Any) -> "FloatSocket":
|
|
59
|
+
def __truediv__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
55
60
|
return self._apply_math_operation(other, "divide")
|
|
56
61
|
|
|
57
|
-
def __rtruediv__(self, other: Any) -> "FloatSocket":
|
|
62
|
+
def __rtruediv__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
58
63
|
return self._apply_math_operation(other, "divide", reverse=True)
|
|
59
64
|
|
|
60
|
-
def __add__(self, other: Any) -> "FloatSocket":
|
|
65
|
+
def __add__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
61
66
|
return self._apply_math_operation(other, "add")
|
|
62
67
|
|
|
63
|
-
def __radd__(self, other: Any) -> "FloatSocket":
|
|
68
|
+
def __radd__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
64
69
|
return self._apply_math_operation(other, "add", reverse=True)
|
|
65
70
|
|
|
66
|
-
def __sub__(self, other: Any) -> "FloatSocket":
|
|
71
|
+
def __sub__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
67
72
|
return self._apply_math_operation(other, "subtract")
|
|
68
73
|
|
|
69
|
-
def __rsub__(self, other: Any) -> "FloatSocket":
|
|
74
|
+
def __rsub__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
70
75
|
return self._apply_math_operation(other, "subtract", reverse=True)
|
|
71
76
|
|
|
72
|
-
def __pow__(self, other: Any) -> "FloatSocket":
|
|
77
|
+
def __pow__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
73
78
|
return self._apply_math_operation(other, "power")
|
|
74
79
|
|
|
75
|
-
def __rpow__(self, other: Any) -> "FloatSocket":
|
|
80
|
+
def __rpow__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
76
81
|
return self._apply_math_operation(other, "power", reverse=True)
|
|
77
82
|
|
|
78
|
-
def __mod__(self, other: Any) -> "FloatSocket":
|
|
83
|
+
def __mod__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
79
84
|
return self._apply_math_operation(other, "modulo")
|
|
80
85
|
|
|
81
|
-
def __rmod__(self, other: Any) -> "FloatSocket":
|
|
86
|
+
def __rmod__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
82
87
|
return self._apply_math_operation(other, "modulo", reverse=True)
|
|
83
88
|
|
|
84
|
-
def __floordiv__(self, other: Any) -> "FloatSocket":
|
|
89
|
+
def __floordiv__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
85
90
|
socket, other, reverse = _resolve_promotion(
|
|
86
91
|
self._default_output_socket,
|
|
87
92
|
other,
|
|
88
|
-
False,
|
|
93
|
+
False,
|
|
89
94
|
)
|
|
90
95
|
return _get_socket_linker(socket)._dispatch_floordiv(other, reverse)
|
|
91
96
|
|
|
92
|
-
def __rfloordiv__(self, other: Any) -> "FloatSocket":
|
|
97
|
+
def __rfloordiv__(self, other: Any) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
93
98
|
socket, other, reverse = _resolve_promotion(
|
|
94
99
|
self._default_output_socket,
|
|
95
100
|
other,
|
|
96
|
-
True,
|
|
101
|
+
True,
|
|
97
102
|
)
|
|
98
103
|
return _get_socket_linker(socket)._dispatch_floordiv(other, reverse)
|
|
99
104
|
|
|
100
|
-
def __neg__(self) -> "FloatSocket":
|
|
101
|
-
return _get_socket_linker(self._default_output_socket)._dispatch_unary(
|
|
102
|
-
"negate"
|
|
103
|
-
)
|
|
105
|
+
def __neg__(self) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
106
|
+
return _get_socket_linker(self._default_output_socket)._dispatch_unary("negate")
|
|
104
107
|
|
|
105
|
-
def __abs__(self) -> "FloatSocket":
|
|
106
|
-
return _get_socket_linker(self._default_output_socket)._dispatch_unary(
|
|
108
|
+
def __abs__(self) -> "FloatSocket | VectorSocket | IntegerSocket":
|
|
109
|
+
return _get_socket_linker(self._default_output_socket)._dispatch_unary(
|
|
107
110
|
"absolute"
|
|
108
111
|
)
|
|
109
112
|
|
|
@@ -111,28 +114,28 @@ class OperatorMixin:
|
|
|
111
114
|
self, other: Any, operation: str
|
|
112
115
|
) -> "FloatSocket | BooleanSocket":
|
|
113
116
|
socket, other, _ = _resolve_promotion(
|
|
114
|
-
self._default_output_socket,
|
|
117
|
+
self._default_output_socket,
|
|
115
118
|
other,
|
|
116
119
|
False,
|
|
117
120
|
)
|
|
118
121
|
return _get_socket_linker(socket)._dispatch_compare(other, operation)
|
|
119
122
|
|
|
120
|
-
def __lt__(self, other: Any) -> "BooleanSocket":
|
|
123
|
+
def __lt__(self, other: Any) -> "FloatSocket | BooleanSocket":
|
|
121
124
|
return self._apply_compare_operation(other, "less_than")
|
|
122
125
|
|
|
123
|
-
def __gt__(self, other: Any) -> "
|
|
126
|
+
def __gt__(self, other: Any) -> "FloatSocket | BooleanSocket":
|
|
124
127
|
return self._apply_compare_operation(other, "greater_than")
|
|
125
128
|
|
|
126
|
-
def __le__(self, other: Any) -> "
|
|
129
|
+
def __le__(self, other: Any) -> "FloatSocket | BooleanSocket":
|
|
127
130
|
return self._apply_compare_operation(other, "less_equal")
|
|
128
131
|
|
|
129
|
-
def __ge__(self, other: Any) -> "
|
|
132
|
+
def __ge__(self, other: Any) -> "FloatSocket | BooleanSocket":
|
|
130
133
|
return self._apply_compare_operation(other, "greater_equal")
|
|
131
134
|
|
|
132
|
-
def __eq__(self, other: Any) -> "
|
|
135
|
+
def __eq__(self, other: Any) -> "FloatSocket | BooleanSocket": # type: ignore
|
|
133
136
|
return self._apply_compare_operation(other, "equal")
|
|
134
137
|
|
|
135
|
-
def __ne__(self, other: Any) -> "
|
|
138
|
+
def __ne__(self, other: Any) -> "FloatSocket | BooleanSocket": # type: ignore
|
|
136
139
|
return self._apply_compare_operation(other, "not_equal")
|
|
137
140
|
|
|
138
141
|
def _apply_boolean_operation(self, other: Any, operation: str):
|
|
@@ -146,7 +149,7 @@ class OperatorMixin:
|
|
|
146
149
|
def __rand__(self, other: Any):
|
|
147
150
|
from ..nodes.geometry.converter import BooleanMath
|
|
148
151
|
|
|
149
|
-
return BooleanMath.l_and(other, self)
|
|
152
|
+
return BooleanMath.l_and(other, cast(Any, self))
|
|
150
153
|
|
|
151
154
|
def __or__(self, other: Any):
|
|
152
155
|
return self._apply_boolean_operation(other, "l_or")
|
|
@@ -154,7 +157,7 @@ class OperatorMixin:
|
|
|
154
157
|
def __ror__(self, other: Any):
|
|
155
158
|
from ..nodes.geometry.converter import BooleanMath
|
|
156
159
|
|
|
157
|
-
return BooleanMath.l_or(other, self)
|
|
160
|
+
return BooleanMath.l_or(other, cast(Any, self))
|
|
158
161
|
|
|
159
162
|
def __xor__(self, other: Any):
|
|
160
163
|
return self._apply_boolean_operation(other, "not_equal")
|
|
@@ -162,12 +165,12 @@ class OperatorMixin:
|
|
|
162
165
|
def __rxor__(self, other: Any):
|
|
163
166
|
from ..nodes.geometry.converter import BooleanMath
|
|
164
167
|
|
|
165
|
-
return BooleanMath.not_equal(other, self)
|
|
168
|
+
return BooleanMath.not_equal(other, cast(Any, self))
|
|
166
169
|
|
|
167
170
|
def __invert__(self):
|
|
168
171
|
from ..nodes.geometry.converter import BooleanMath
|
|
169
172
|
|
|
170
|
-
return BooleanMath.l_not(self)
|
|
173
|
+
return BooleanMath.l_not(cast(Any, self))
|
|
171
174
|
|
|
172
175
|
@staticmethod
|
|
173
176
|
def _cast_to_matrix(value) -> MatrixSocket:
|
|
@@ -214,6 +217,20 @@ class LinkingMixin:
|
|
|
214
217
|
|
|
215
218
|
tree: "TreeBuilder"
|
|
216
219
|
|
|
220
|
+
if TYPE_CHECKING:
|
|
221
|
+
import bpy
|
|
222
|
+
|
|
223
|
+
node: bpy.types.Node
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def i(self) -> "SocketAccessor": ...
|
|
227
|
+
|
|
228
|
+
@property
|
|
229
|
+
def o(self) -> "SocketAccessor": ...
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def _default_output_socket(self) -> "NodeSocket": ...
|
|
233
|
+
|
|
217
234
|
def _source_socket(self, node: "InputLinkable | Socket | NodeSocket") -> NodeSocket:
|
|
218
235
|
assert node is not None
|
|
219
236
|
if isinstance(node, NodeSocket):
|
|
@@ -254,8 +271,12 @@ class LinkingMixin:
|
|
|
254
271
|
|
|
255
272
|
if isinstance(target, BaseNode):
|
|
256
273
|
inputs = target.i._available
|
|
257
|
-
|
|
274
|
+
elif isinstance(target, Socket):
|
|
275
|
+
inputs = [target.socket]
|
|
276
|
+
elif isinstance(target, NodeSocket):
|
|
258
277
|
inputs = [target]
|
|
278
|
+
else:
|
|
279
|
+
raise TypeError(f"Cannot get inputs from {type(target)}")
|
|
259
280
|
|
|
260
281
|
# NodeReroute adapts its type to whatever is linked — skip type matching
|
|
261
282
|
if getattr(getattr(target, "node", None), "bl_idname", None) == "NodeReroute":
|
|
@@ -291,8 +312,10 @@ class LinkingMixin:
|
|
|
291
312
|
if possible_combos:
|
|
292
313
|
return sorted(possible_combos, key=lambda x: x[0])[0][1]
|
|
293
314
|
|
|
315
|
+
src_name = getattr(getattr(source, "node", None), "name", repr(source))
|
|
316
|
+
tgt_name = getattr(getattr(target, "node", None), "name", repr(target))
|
|
294
317
|
raise SocketError(
|
|
295
|
-
f"Cannot link any output from {
|
|
318
|
+
f"Cannot link any output from {src_name} to any input of {tgt_name}. "
|
|
296
319
|
f"Available output types: {[f'{o.name}:{o.type}' for o in outputs]}, "
|
|
297
320
|
f"Available input types: {[f'{i.name}:{i.type}' for i in inputs]}"
|
|
298
321
|
)
|
|
@@ -333,17 +356,24 @@ class LinkingMixin:
|
|
|
333
356
|
source = self._default_output_socket
|
|
334
357
|
target = other.socket
|
|
335
358
|
elif getattr(other, "_placeholder_inputs", None):
|
|
336
|
-
|
|
359
|
+
node_other = cast("BaseNode", other)
|
|
360
|
+
name = node_other._placeholder_inputs.pop(0)
|
|
337
361
|
try:
|
|
338
|
-
target =
|
|
362
|
+
target = node_other.node.inputs[name]
|
|
339
363
|
except KeyError:
|
|
340
|
-
target =
|
|
341
|
-
source =
|
|
364
|
+
target = node_other.node.inputs[node_other.i._index(name)]
|
|
365
|
+
source = (
|
|
366
|
+
self.o._best_match(target.type)
|
|
367
|
+
if hasattr(self, "o")
|
|
368
|
+
else self._default_output_socket
|
|
369
|
+
)
|
|
342
370
|
else:
|
|
343
371
|
try:
|
|
344
|
-
source, target = self._find_best_socket_pair(self, other)
|
|
372
|
+
source, target = self._find_best_socket_pair(self, cast(Any, other))
|
|
345
373
|
except SocketError:
|
|
346
|
-
source, target =
|
|
374
|
+
source, target = cast("LinkingMixin", other)._find_best_socket_pair(
|
|
375
|
+
self, cast(Any, other)
|
|
376
|
+
)
|
|
347
377
|
|
|
348
378
|
self.tree.link(source, target)
|
|
349
379
|
return other
|
|
@@ -138,9 +138,9 @@ class BaseNode(_NodeLike, OperatorMixin, LinkingMixin):
|
|
|
138
138
|
and input.type == "VECTOR"
|
|
139
139
|
and isinstance(value, (int, float))
|
|
140
140
|
):
|
|
141
|
-
input.default_value = [value] * len(input.default_value)
|
|
141
|
+
input.default_value = [value] * len(input.default_value) # type: ignore
|
|
142
142
|
else:
|
|
143
|
-
input.default_value = value
|
|
143
|
+
input.default_value = value # type: ignore
|
|
144
144
|
|
|
145
145
|
def _establish_links(self, **kwargs: InputAny):
|
|
146
146
|
input_ids = [input.identifier for input in self.node.inputs]
|
|
@@ -165,7 +165,7 @@ class BaseNode(_NodeLike, OperatorMixin, LinkingMixin):
|
|
|
165
165
|
elif isinstance(value, NodeSocket):
|
|
166
166
|
self._link_from(value, name)
|
|
167
167
|
elif isinstance(value, _NodeLike):
|
|
168
|
-
self._link_from(value.o._best_match(self.i._get(name).type), name)
|
|
168
|
+
self._link_from(value.o._best_match(self.i._get(name).type), name) # type: ignore
|
|
169
169
|
else:
|
|
170
170
|
if name in input_ids:
|
|
171
171
|
input = self.node.inputs[input_ids.index(name)]
|