nodebpy 0.15.0__tar.gz → 0.16.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.
Files changed (68) hide show
  1. {nodebpy-0.15.0 → nodebpy-0.16.0}/PKG-INFO +1 -1
  2. {nodebpy-0.15.0 → nodebpy-0.16.0}/pyproject.toml +2 -1
  3. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/builder/accessor.py +13 -2
  4. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/builder/mixins.py +42 -29
  5. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/builder/node.py +6 -4
  6. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/builder/socket.py +538 -333
  7. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/builder/tree.py +1 -1
  8. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/manual.py +6 -2
  9. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/attribute.py +2 -1
  10. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/groups.py +5 -9
  11. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/manual.py +7 -70
  12. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/manual.py +2 -2
  13. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/types.py +1 -1
  14. {nodebpy-0.15.0 → nodebpy-0.16.0}/README.md +0 -0
  15. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/__init__.py +0 -0
  16. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/arrange.py +0 -0
  17. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/builder/__init__.py +0 -0
  18. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/builder/_registry.py +0 -0
  19. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/builder/_utils.py +0 -0
  20. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/diagram.py +0 -0
  21. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/__init__.py +0 -0
  22. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/arrange/graph.py +0 -0
  23. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/arrange/ordering.py +0 -0
  24. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/arrange/ranking.py +0 -0
  25. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/arrange/realize.py +0 -0
  26. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/arrange/stacking.py +0 -0
  27. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/arrange/structs.py +0 -0
  28. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/arrange/sugiyama.py +0 -0
  29. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/arrange/x_coords.py +0 -0
  30. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/arrange/y_coords.py +0 -0
  31. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/config.py +0 -0
  32. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/lib/nodearrange/utils.py +0 -0
  33. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/__init__.py +0 -0
  34. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/__init__.py +0 -0
  35. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/color.py +0 -0
  36. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/converter.py +0 -0
  37. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/distort.py +0 -0
  38. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/filter.py +0 -0
  39. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/group.py +0 -0
  40. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/input.py +0 -0
  41. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/interface.py +0 -0
  42. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/matte.py +0 -0
  43. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/output.py +0 -0
  44. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/compositor/vector.py +0 -0
  45. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/__init__.py +0 -0
  46. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/color.py +0 -0
  47. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/converter.py +0 -0
  48. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/geometry.py +0 -0
  49. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/grid.py +0 -0
  50. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/group.py +0 -0
  51. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/input.py +0 -0
  52. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/interface.py +0 -0
  53. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/output.py +0 -0
  54. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/texture.py +0 -0
  55. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/utilities.py +0 -0
  56. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/vector.py +0 -0
  57. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/geometry/zone.py +0 -0
  58. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/__init__.py +0 -0
  59. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/color.py +0 -0
  60. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/converter.py +0 -0
  61. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/grid.py +0 -0
  62. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/group.py +0 -0
  63. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/input.py +0 -0
  64. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/output.py +0 -0
  65. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/script.py +0 -0
  66. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/shader.py +0 -0
  67. {nodebpy-0.15.0 → nodebpy-0.16.0}/src/nodebpy/nodes/shader/texture.py +0 -0
  68. {nodebpy-0.15.0 → nodebpy-0.16.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.15.0
3
+ Version: 0.16.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>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nodebpy"
3
- version = "0.15.0"
3
+ version = "0.16.0"
4
4
  description = "Build nodes trees in Blender more elegantly with code"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -38,4 +38,5 @@ 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
42
  ]
@@ -14,6 +14,7 @@ from ._utils import (
14
14
  )
15
15
 
16
16
  if TYPE_CHECKING:
17
+ from .node import BaseNode
17
18
  from .socket import Socket
18
19
 
19
20
 
@@ -30,9 +31,12 @@ class SocketAccessor:
30
31
  self,
31
32
  collection: bpy.types.NodeInputs | bpy.types.NodeOutputs | list[NodeSocket],
32
33
  direction: Literal["input", "output"],
34
+ *,
35
+ builder: BaseNode | None = None,
33
36
  ):
34
37
  self._direction = direction
35
38
  self._collection = collection
39
+ self._builder = builder
36
40
 
37
41
  def _index(self, key: str | int) -> int:
38
42
  """Find socket index by identifier, falling back to name.
@@ -74,11 +78,18 @@ class SocketAccessor:
74
78
  def _get(self, key: str | int | slice) -> "Socket | list[Socket]":
75
79
  """Get a Socket for a socket by identifier, name, or index."""
76
80
  if isinstance(key, slice):
77
- return [
81
+ sockets = [
78
82
  _get_socket_linker(self._collection[i])
79
83
  for i in range(*key.indices(len(self._collection)))
80
84
  ]
81
- return _get_socket_linker(self._collection[self._index(key)])
85
+ if self._builder is not None:
86
+ for s in sockets:
87
+ s._builder_node = self._builder
88
+ return sockets
89
+ socket = _get_socket_linker(self._collection[self._index(key)])
90
+ if self._builder is not None:
91
+ socket._builder_node = self._builder
92
+ return socket
82
93
 
83
94
  @overload
84
95
  def __getitem__(self, key: slice) -> "list[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
4
+ from typing import TYPE_CHECKING, Any, TypeVar, overload
5
5
 
6
6
  from bpy.types import NodeLink, NodeSocket
7
7
 
@@ -14,7 +14,14 @@ if TYPE_CHECKING:
14
14
  from ..nodes.geometry import Compare, Math, MultiplyMatrices, TransformPoint
15
15
  from ..types import InputLinkable
16
16
  from .node import BaseNode
17
- from .socket import MatrixSocket, Socket
17
+ from .socket import (
18
+ BooleanSocket,
19
+ FloatSocket,
20
+ IntegerSocket,
21
+ MatrixSocket,
22
+ Socket,
23
+ VectorSocket,
24
+ )
18
25
  from .tree import TreeBuilder
19
26
 
20
27
 
@@ -30,7 +37,7 @@ class OperatorMixin:
30
37
 
31
38
  def _apply_math_operation(
32
39
  self, other: Any, operation: str, reverse: bool = False
33
- ) -> "Math":
40
+ ) -> "FloatSocket | VectorSocket | IntegerSocket":
34
41
  socket, other, reverse = _resolve_promotion(
35
42
  self._default_output_socket,
36
43
  other,
@@ -38,43 +45,43 @@ class OperatorMixin:
38
45
  )
39
46
  return _get_socket_linker(socket)._dispatch_math(other, operation, reverse)
40
47
 
41
- def __mul__(self, other: Any) -> "Math":
48
+ def __mul__(self, other: Any) -> "FloatSocket":
42
49
  return self._apply_math_operation(other, "multiply")
43
50
 
44
- def __rmul__(self, other: Any) -> "Math":
51
+ def __rmul__(self, other: Any) -> "FloatSocket":
45
52
  return self._apply_math_operation(other, "multiply", reverse=True)
46
53
 
47
- def __truediv__(self, other: Any) -> "Math":
54
+ def __truediv__(self, other: Any) -> "FloatSocket":
48
55
  return self._apply_math_operation(other, "divide")
49
56
 
50
- def __rtruediv__(self, other: Any) -> "Math":
57
+ def __rtruediv__(self, other: Any) -> "FloatSocket":
51
58
  return self._apply_math_operation(other, "divide", reverse=True)
52
59
 
53
- def __add__(self, other: Any) -> "Math":
60
+ def __add__(self, other: Any) -> "FloatSocket":
54
61
  return self._apply_math_operation(other, "add")
55
62
 
56
- def __radd__(self, other: Any) -> "Math":
63
+ def __radd__(self, other: Any) -> "FloatSocket":
57
64
  return self._apply_math_operation(other, "add", reverse=True)
58
65
 
59
- def __sub__(self, other: Any) -> "Math":
66
+ def __sub__(self, other: Any) -> "FloatSocket":
60
67
  return self._apply_math_operation(other, "subtract")
61
68
 
62
- def __rsub__(self, other: Any) -> "Math":
69
+ def __rsub__(self, other: Any) -> "FloatSocket":
63
70
  return self._apply_math_operation(other, "subtract", reverse=True)
64
71
 
65
- def __pow__(self, other: Any) -> "Math":
72
+ def __pow__(self, other: Any) -> "FloatSocket":
66
73
  return self._apply_math_operation(other, "power")
67
74
 
68
- def __rpow__(self, other: Any) -> "Math":
75
+ def __rpow__(self, other: Any) -> "FloatSocket":
69
76
  return self._apply_math_operation(other, "power", reverse=True)
70
77
 
71
- def __mod__(self, other: Any) -> "Math":
78
+ def __mod__(self, other: Any) -> "FloatSocket":
72
79
  return self._apply_math_operation(other, "modulo")
73
80
 
74
- def __rmod__(self, other: Any) -> "Math":
81
+ def __rmod__(self, other: Any) -> "FloatSocket":
75
82
  return self._apply_math_operation(other, "modulo", reverse=True)
76
83
 
77
- def __floordiv__(self, other: Any) -> "Math":
84
+ def __floordiv__(self, other: Any) -> "FloatSocket":
78
85
  socket, other, reverse = _resolve_promotion(
79
86
  self._default_output_socket,
80
87
  other,
@@ -82,7 +89,7 @@ class OperatorMixin:
82
89
  )
83
90
  return _get_socket_linker(socket)._dispatch_floordiv(other, reverse)
84
91
 
85
- def __rfloordiv__(self, other: Any) -> "Math":
92
+ def __rfloordiv__(self, other: Any) -> "FloatSocket":
86
93
  socket, other, reverse = _resolve_promotion(
87
94
  self._default_output_socket,
88
95
  other,
@@ -90,17 +97,19 @@ class OperatorMixin:
90
97
  )
91
98
  return _get_socket_linker(socket)._dispatch_floordiv(other, reverse)
92
99
 
93
- def __neg__(self) -> "Math":
100
+ def __neg__(self) -> "FloatSocket":
94
101
  return _get_socket_linker(self._default_output_socket)._dispatch_unary( # type: ignore[attr-defined]
95
102
  "negate"
96
103
  )
97
104
 
98
- def __abs__(self) -> "Math":
105
+ def __abs__(self) -> "FloatSocket":
99
106
  return _get_socket_linker(self._default_output_socket)._dispatch_unary( # type: ignore[attr-defined]
100
107
  "absolute"
101
108
  )
102
109
 
103
- def _apply_compare_operation(self, other: Any, operation: str) -> "Math":
110
+ def _apply_compare_operation(
111
+ self, other: Any, operation: str
112
+ ) -> "FloatSocket | BooleanSocket":
104
113
  socket, other, _ = _resolve_promotion(
105
114
  self._default_output_socket, # type: ignore[attr-defined]
106
115
  other,
@@ -108,7 +117,7 @@ class OperatorMixin:
108
117
  )
109
118
  return _get_socket_linker(socket)._dispatch_compare(other, operation)
110
119
 
111
- def __lt__(self, other: Any) -> "Compare":
120
+ def __lt__(self, other: Any) -> "BooleanSocket":
112
121
  return self._apply_compare_operation(other, "less_than")
113
122
 
114
123
  def __gt__(self, other: Any) -> "Compare":
@@ -169,27 +178,31 @@ class OperatorMixin:
169
178
  else:
170
179
  return value
171
180
 
172
- def __matmul__(self, other: Any) -> "MultiplyMatrices | TransformPoint":
181
+ def __matmul__(self, other: Any) -> "MatrixSocket | VectorSocket":
173
182
  from ..nodes.geometry.converter import MultiplyMatrices, TransformPoint
174
183
 
175
184
  other = self._cast_to_matrix(other)
176
185
  socket = self._default_output_socket
177
186
 
178
187
  if socket.type == "MATRIX" and other.type == "VECTOR":
179
- return TransformPoint(other, socket)
188
+ return TransformPoint(other, socket).o.vector
180
189
 
181
- return MultiplyMatrices(socket, other)
190
+ return MultiplyMatrices(socket, other).o.matrix
182
191
 
183
- def __rmatmul__(self, other: Any) -> "MultiplyMatrices | TransformPoint":
192
+ @overload
193
+ def __rmatmul__(self, other: MatrixSocket) -> "MatrixSocket": ...
194
+ @overload
195
+ def __rmatmul__(self, other: VectorSocket) -> "VectorSocket": ...
196
+ def __rmatmul__(self, other: Any) -> "MatrixSocket | VectorSocket":
184
197
  from ..nodes.geometry.converter import MultiplyMatrices, TransformPoint
185
198
 
186
199
  other = self._cast_to_matrix(other)
187
200
  socket = self._default_output_socket
188
201
 
189
202
  if socket.type == "VECTOR" and getattr(other, "type", None) == "MATRIX":
190
- return TransformPoint(socket, other)
203
+ return TransformPoint(socket, other).o.vector
191
204
 
192
- return MultiplyMatrices(other, socket)
205
+ return MultiplyMatrices(other, socket).o.matrix
193
206
 
194
207
 
195
208
  class LinkingMixin:
@@ -202,7 +215,7 @@ class LinkingMixin:
202
215
  tree: "TreeBuilder"
203
216
 
204
217
  def _source_socket(self, node: "InputLinkable | Socket | NodeSocket") -> NodeSocket:
205
- assert node
218
+ assert node is not None
206
219
  if isinstance(node, NodeSocket):
207
220
  return node
208
221
  elif hasattr(node, "_default_output_socket"):
@@ -211,7 +224,7 @@ class LinkingMixin:
211
224
  raise TypeError(f"Unsupported type: {type(node)}")
212
225
 
213
226
  def _target_socket(self, node: "InputLinkable | Socket | NodeSocket") -> NodeSocket:
214
- assert node
227
+ assert node is not None
215
228
  if isinstance(node, NodeSocket):
216
229
  return node
217
230
  elif hasattr(node, "_default_input_socket"):
@@ -21,6 +21,7 @@ from bpy.types import (
21
21
  GeometryNodeTree,
22
22
  Node,
23
23
  NodeSocket,
24
+ NodeTree,
24
25
  ShaderNodeGroup,
25
26
  ShaderNodeTree,
26
27
  )
@@ -101,8 +102,9 @@ class BaseNode(_NodeLike, OperatorMixin, LinkingMixin):
101
102
 
102
103
  @classmethod
103
104
  def _from_node(cls, node: Node) -> Self:
104
- builder = cls()
105
- builder.tree.nodes.remove(builder.node)
105
+ builder = cls.__new__(cls)
106
+ builder._tree = TreeBuilder(cast(NodeTree, node.id_data))
107
+ builder._placeholder_inputs = []
106
108
  builder.node = node
107
109
  return builder
108
110
 
@@ -178,12 +180,12 @@ class BaseNode(_NodeLike, OperatorMixin, LinkingMixin):
178
180
  @property
179
181
  def o(self) -> SocketAccessor:
180
182
  """Output socket accessor. Subclasses narrow the return type via TYPE_CHECKING."""
181
- return SocketAccessor(self.node.outputs, "output")
183
+ return SocketAccessor(self.node.outputs, "output", builder=self)
182
184
 
183
185
  @property
184
186
  def i(self) -> SocketAccessor:
185
187
  """Input socket accessor. Subclasses narrow the return type via TYPE_CHECKING."""
186
- return SocketAccessor(self.node.inputs, "input")
188
+ return SocketAccessor(self.node.inputs, "input", builder=self)
187
189
 
188
190
 
189
191
  class DynamicInputsMixin(ABC):