nodebpy 0.7.1__tar.gz → 0.7.2__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.7.1 → nodebpy-0.7.2}/PKG-INFO +1 -1
- {nodebpy-0.7.1 → nodebpy-0.7.2}/pyproject.toml +1 -1
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/builder.py +58 -28
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/types.py +2 -1
- {nodebpy-0.7.1 → nodebpy-0.7.2}/README.md +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/__init__.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/arrange.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/__init__.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/arrange/graph.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/arrange/ordering.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/arrange/ranking.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/arrange/realize.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/arrange/stacking.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/arrange/structs.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/arrange/sugiyama.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/arrange/x_coords.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/arrange/y_coords.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/config.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/lib/nodearrange/utils.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/__init__.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/__init__.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/color.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/converter.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/distort.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/filter.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/group.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/input.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/interface.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/manual.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/matte.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/output.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/texture.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/compositor/vector.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/__init__.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/attribute.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/color.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/converter.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/geometry.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/grid.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/group.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/input.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/interface.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/manual.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/output.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/texture.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/vector.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/geometry/zone.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/__init__.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/color.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/converter.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/grid.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/group.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/input.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/interface.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/manual.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/output.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/script.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/shader.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/texture.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/vector.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/nodes/shader/zone.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/screenshot.py +0 -0
- {nodebpy-0.7.1 → nodebpy-0.7.2}/src/nodebpy/sockets.py +0 -0
|
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any, ClassVar, Iterable, Literal
|
|
|
4
4
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
6
|
from .nodes.geometry import IntegerMath, Math, VectorMath
|
|
7
|
-
from .nodes.geometry.converter import BooleanMath, MultiplyMatrices
|
|
7
|
+
from .nodes.geometry.converter import BooleanMath, MultiplyMatrices, TransformPoint
|
|
8
8
|
from .nodes.geometry.manual import Compare
|
|
9
9
|
|
|
10
10
|
import bpy
|
|
@@ -139,7 +139,7 @@ class SocketContext:
|
|
|
139
139
|
class DirectionalContext(SocketContext):
|
|
140
140
|
"""Base class for directional socket contexts"""
|
|
141
141
|
|
|
142
|
-
_direction
|
|
142
|
+
_direction = "INPUT"
|
|
143
143
|
_active_context = None
|
|
144
144
|
|
|
145
145
|
|
|
@@ -249,14 +249,14 @@ class TreeBuilder:
|
|
|
249
249
|
|
|
250
250
|
@fake_user.setter
|
|
251
251
|
def fake_user(self, value: bool) -> None:
|
|
252
|
-
self.tree.
|
|
252
|
+
self.tree.use_fake_user = value
|
|
253
253
|
|
|
254
254
|
def activate_tree(self) -> None:
|
|
255
255
|
"""Make this tree the active tree for all new node creation."""
|
|
256
256
|
TreeBuilder._tree_contexts.append(self)
|
|
257
257
|
|
|
258
258
|
def deactivate_tree(self) -> None:
|
|
259
|
-
"""Whatever tree
|
|
259
|
+
"""Whatever tree was previously active is set to be the active one (or None if no previously active tree)."""
|
|
260
260
|
TreeBuilder._tree_contexts.pop()
|
|
261
261
|
|
|
262
262
|
def __enter__(self):
|
|
@@ -271,9 +271,9 @@ class TreeBuilder:
|
|
|
271
271
|
|
|
272
272
|
def _apply_input_defaults(self) -> None:
|
|
273
273
|
for key, value in self._menu_defaults.items():
|
|
274
|
-
for item in self.tree.interface.items_tree:
|
|
275
|
-
if item.identifier == key:
|
|
276
|
-
item.default_value = value
|
|
274
|
+
for item in self.tree.interface.items_tree: # type: ignore
|
|
275
|
+
if item.identifier == key: # type: ignore
|
|
276
|
+
item.default_value = value # type: ignore
|
|
277
277
|
break
|
|
278
278
|
|
|
279
279
|
def __len__(self) -> int:
|
|
@@ -336,7 +336,7 @@ class TreeBuilder:
|
|
|
336
336
|
for socket in [socket1, socket2]:
|
|
337
337
|
# we want to be loud about it if we end up linking an inactive socket to a node that is not a switch
|
|
338
338
|
if socket.is_inactive and (
|
|
339
|
-
socket.node.bl_idname
|
|
339
|
+
socket.node.bl_idname # type: ignore
|
|
340
340
|
not in ( # type: ignore
|
|
341
341
|
"GeometryNodeIndexSwitch",
|
|
342
342
|
"GeometryNodeMenuSwitch",
|
|
@@ -360,13 +360,14 @@ class TreeBuilder:
|
|
|
360
360
|
class NodeBuilder:
|
|
361
361
|
"""Base class for all geometry node wrappers."""
|
|
362
362
|
|
|
363
|
-
node:
|
|
363
|
+
node: bpy.types.Node
|
|
364
364
|
_bl_idname: str
|
|
365
365
|
_tree: "TreeBuilder"
|
|
366
366
|
_link_target: str | None = None
|
|
367
367
|
_from_socket: NodeSocket | None = None
|
|
368
368
|
_default_input_id: str | None = None
|
|
369
369
|
_default_output_id: str | None = None
|
|
370
|
+
_placeholder_inputs: list[str]
|
|
370
371
|
__array_ufunc__ = None
|
|
371
372
|
|
|
372
373
|
def __init__(self):
|
|
@@ -384,6 +385,7 @@ class NodeBuilder:
|
|
|
384
385
|
|
|
385
386
|
self._tree = tree
|
|
386
387
|
self._link_target = None
|
|
388
|
+
self._placeholder_inputs = []
|
|
387
389
|
if self.__class__.name is not None:
|
|
388
390
|
self.node = self._tree.add(self.__class__._bl_idname)
|
|
389
391
|
else:
|
|
@@ -506,7 +508,7 @@ class NodeBuilder:
|
|
|
506
508
|
return sorted(possible_combos, key=lambda x: x[0])[0][1]
|
|
507
509
|
|
|
508
510
|
raise SocketError(
|
|
509
|
-
f"Cannot link any output from {source.node.name} to any input of {target.node.name}. "
|
|
511
|
+
f"Cannot link any output from {source.node.name} to any input of {target.node.name}. " # type: ignore
|
|
510
512
|
f"Available output types: {[f'{o.name}:{o.type}' for o in outputs]}, "
|
|
511
513
|
f"Available input types: {[f'{i.name}:{i.type}' for i in inputs]}"
|
|
512
514
|
)
|
|
@@ -530,7 +532,10 @@ class NodeBuilder:
|
|
|
530
532
|
if identifier in input_names:
|
|
531
533
|
return input_names.index(identifier)
|
|
532
534
|
|
|
533
|
-
raise RuntimeError(
|
|
535
|
+
raise RuntimeError(
|
|
536
|
+
f"Input '{identifier}' not found on {self.node.bl_idname}. "
|
|
537
|
+
f"Available inputs: {input_names}"
|
|
538
|
+
)
|
|
534
539
|
|
|
535
540
|
def _output_idx(self, identifier: str) -> int:
|
|
536
541
|
output_ids = [output.identifier for output in self.node.outputs]
|
|
@@ -593,10 +598,11 @@ class NodeBuilder:
|
|
|
593
598
|
value = node
|
|
594
599
|
|
|
595
600
|
if value is ...:
|
|
596
|
-
# Ellipsis
|
|
597
|
-
|
|
601
|
+
# Ellipsis marks this input as a placeholder for the >> operator
|
|
602
|
+
self._placeholder_inputs.append(name)
|
|
598
603
|
if self._from_socket is not None:
|
|
599
604
|
self._link_from(self._from_socket, name)
|
|
605
|
+
continue
|
|
600
606
|
|
|
601
607
|
elif isinstance(value, SocketLinker):
|
|
602
608
|
self._link_from(value, name)
|
|
@@ -628,6 +634,14 @@ class NodeBuilder:
|
|
|
628
634
|
source = self._default_output_socket
|
|
629
635
|
target = other.socket
|
|
630
636
|
other._from_socket = source
|
|
637
|
+
elif getattr(other, "_placeholder_inputs", None):
|
|
638
|
+
# Link to the first placeholder input marked with ...
|
|
639
|
+
name = other._placeholder_inputs.pop(0)
|
|
640
|
+
try:
|
|
641
|
+
target = other.node.inputs[name]
|
|
642
|
+
except KeyError:
|
|
643
|
+
target = other.node.inputs[other._input_idx(name)]
|
|
644
|
+
source = self._best_output_socket(target.type)
|
|
631
645
|
else:
|
|
632
646
|
try:
|
|
633
647
|
source, target = self._find_best_socket_pair(self, other)
|
|
@@ -701,7 +715,7 @@ class NodeBuilder:
|
|
|
701
715
|
|
|
702
716
|
# only the Geometry Node Tree supports integer math currently, potential
|
|
703
717
|
# to support other trees when Blender supports it
|
|
704
|
-
is_geometry_tree = self._tree.tree.bl_idname
|
|
718
|
+
is_geometry_tree = self._tree.tree.bl_idname == "GeometryNodeTree"
|
|
705
719
|
if (
|
|
706
720
|
is_geometry_tree
|
|
707
721
|
and isinstance(other, int)
|
|
@@ -846,16 +860,16 @@ class NodeBuilder:
|
|
|
846
860
|
result = Math.subtract(1.0, result._default_output_socket)
|
|
847
861
|
return result
|
|
848
862
|
|
|
849
|
-
def __lt__(self, other: Any) -> "Compare":
|
|
863
|
+
def __lt__(self, other: Any) -> "Compare | Math":
|
|
850
864
|
return self._apply_compare_operation(other, "less_than")
|
|
851
865
|
|
|
852
|
-
def __gt__(self, other: Any) -> "Compare":
|
|
866
|
+
def __gt__(self, other: Any) -> "Compare | Math":
|
|
853
867
|
return self._apply_compare_operation(other, "greater_than")
|
|
854
868
|
|
|
855
|
-
def __le__(self, other: Any) -> "Compare":
|
|
869
|
+
def __le__(self, other: Any) -> "Compare | Math":
|
|
856
870
|
return self._apply_compare_operation(other, "less_equal")
|
|
857
871
|
|
|
858
|
-
def __ge__(self, other: Any) -> "Compare":
|
|
872
|
+
def __ge__(self, other: Any) -> "Compare | Math":
|
|
859
873
|
return self._apply_compare_operation(other, "greater_equal")
|
|
860
874
|
|
|
861
875
|
def _apply_boolean_operation(self, other: Any, operation: str) -> "BooleanMath":
|
|
@@ -902,15 +916,31 @@ class NodeBuilder:
|
|
|
902
916
|
else:
|
|
903
917
|
return value
|
|
904
918
|
|
|
905
|
-
def __matmul__(self, other: Any) -> "MultiplyMatrices":
|
|
906
|
-
from .nodes.geometry.converter import MultiplyMatrices
|
|
919
|
+
def __matmul__(self, other: Any) -> "MultiplyMatrices | TransformPoint":
|
|
920
|
+
from .nodes.geometry.converter import MultiplyMatrices, TransformPoint
|
|
907
921
|
|
|
908
|
-
|
|
922
|
+
other = self._cast_to_matrix(other)
|
|
923
|
+
socket = self._default_output_socket
|
|
924
|
+
other_type = getattr(other, "type", None)
|
|
925
|
+
|
|
926
|
+
# matrix @ vector → TransformPoint (standard M @ v)
|
|
927
|
+
if socket.type == "MATRIX" and other_type == "VECTOR":
|
|
928
|
+
return TransformPoint(other, socket)
|
|
929
|
+
|
|
930
|
+
return MultiplyMatrices(self, other)
|
|
931
|
+
|
|
932
|
+
def __rmatmul__(self, other: Any) -> "MultiplyMatrices | TransformPoint":
|
|
933
|
+
from .nodes.geometry.converter import MultiplyMatrices, TransformPoint
|
|
934
|
+
|
|
935
|
+
other = self._cast_to_matrix(other)
|
|
936
|
+
socket = self._default_output_socket
|
|
937
|
+
other_type = getattr(other, "type", None)
|
|
909
938
|
|
|
910
|
-
|
|
911
|
-
|
|
939
|
+
# matrix @ vector: other is matrix (non-NodeBuilder cast), self is vector
|
|
940
|
+
if socket.type == "VECTOR" and other_type == "MATRIX":
|
|
941
|
+
return TransformPoint(socket, other)
|
|
912
942
|
|
|
913
|
-
return MultiplyMatrices(
|
|
943
|
+
return MultiplyMatrices(other, self)
|
|
914
944
|
|
|
915
945
|
|
|
916
946
|
class DynamicInputsMixin:
|
|
@@ -938,7 +968,7 @@ class DynamicInputsMixin:
|
|
|
938
968
|
self, source: NodeBuilder | NodeSocket, target: NodeBuilder | NodeSocket
|
|
939
969
|
) -> tuple[NodeSocket, NodeSocket]:
|
|
940
970
|
try:
|
|
941
|
-
return super()._find_best_socket_pair(source, target)
|
|
971
|
+
return super()._find_best_socket_pair(source, target) # type: ignore
|
|
942
972
|
except SocketError:
|
|
943
973
|
if target == self:
|
|
944
974
|
target_name, source_socket = list(target._add_inputs(source).items())[0]
|
|
@@ -1030,7 +1060,7 @@ class SocketBase(SocketLinker):
|
|
|
1030
1060
|
def __init__(self, name: str, description: str = ""):
|
|
1031
1061
|
self.description = description
|
|
1032
1062
|
|
|
1033
|
-
self._socket_context
|
|
1063
|
+
self._socket_context = SocketContext._active_context
|
|
1034
1064
|
self.interface_socket = self._socket_context._create_socket(self, name)
|
|
1035
1065
|
self._tree = self._socket_context.builder
|
|
1036
1066
|
if self._socket_context._direction == "INPUT":
|
|
@@ -1060,7 +1090,7 @@ class SocketBase(SocketLinker):
|
|
|
1060
1090
|
raise AttributeError(
|
|
1061
1091
|
f"'{self.__class__.__name__}' object has no attribute 'default_value'"
|
|
1062
1092
|
)
|
|
1063
|
-
return self.interface_socket
|
|
1093
|
+
return getattr(self.interface_socket, "default_value")
|
|
1064
1094
|
|
|
1065
1095
|
@default_value.setter
|
|
1066
1096
|
def default_value(self, value):
|
|
@@ -1068,7 +1098,7 @@ class SocketBase(SocketLinker):
|
|
|
1068
1098
|
raise AttributeError(
|
|
1069
1099
|
f"'{self.__class__.__name__}' object has no attribute 'default_value'"
|
|
1070
1100
|
)
|
|
1071
|
-
self.interface_socket
|
|
1101
|
+
setattr(self.interface_socket, "default_value", value)
|
|
1072
1102
|
|
|
1073
1103
|
|
|
1074
1104
|
class SocketFloat(SocketBase):
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import typing
|
|
4
|
+
from types import EllipsisType
|
|
4
5
|
from typing import Literal
|
|
5
6
|
|
|
6
7
|
from bpy.types import (
|
|
@@ -35,7 +36,7 @@ def _is_default_value(value: TYPE_INPUT_ALL):
|
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
# Type aliases for node inputs using typing.Union for runtime compatibility
|
|
38
|
-
LINKABLE = typing.Union["NodeBuilder", "SocketLinker", NodeSocket, None]
|
|
39
|
+
LINKABLE = typing.Union["NodeBuilder", "SocketLinker", NodeSocket, None, EllipsisType]
|
|
39
40
|
TYPE_INPUT_ROTATION = typing.Union[
|
|
40
41
|
tuple[float, float, float], float, int, Euler, LINKABLE
|
|
41
42
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|