nodebpy 520.3.0__tar.gz → 520.5.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 (80) hide show
  1. {nodebpy-520.3.0 → nodebpy-520.5.0}/PKG-INFO +1 -1
  2. {nodebpy-520.3.0 → nodebpy-520.5.0}/pyproject.toml +2 -2
  3. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/assets/_codegen.py +3 -3
  4. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/asset.py +4 -1
  5. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/mixins.py +12 -2
  6. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/socket.py +0 -1
  7. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/tree.py +1 -1
  8. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/export/codegen.py +1 -1
  9. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/ordering.py +1 -1
  10. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/_mixins.py +1 -1
  11. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/converter.py +3 -3
  12. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/manual.py +3 -3
  13. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/zone.py +2 -2
  14. {nodebpy-520.3.0 → nodebpy-520.5.0}/README.md +0 -0
  15. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/__init__.py +0 -0
  16. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/assets/__init__.py +0 -0
  17. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/assets/__main__.py +0 -0
  18. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/__init__.py +0 -0
  19. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/_registry.py +0 -0
  20. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/_utils.py +0 -0
  21. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/accessor.py +0 -0
  22. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/arrange.py +0 -0
  23. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/items.py +0 -0
  24. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/builder/node.py +0 -0
  25. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/export/__init__.py +0 -0
  26. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/export/diagram.py +0 -0
  27. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/__init__.py +0 -0
  28. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/__init__.py +0 -0
  29. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/graph.py +0 -0
  30. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/ranking.py +0 -0
  31. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/realize.py +0 -0
  32. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/stacking.py +0 -0
  33. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/structs.py +0 -0
  34. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/sugiyama.py +0 -0
  35. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/x_coords.py +0 -0
  36. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/arrange/y_coords.py +0 -0
  37. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/config.py +0 -0
  38. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/lib/nodearrange/utils.py +0 -0
  39. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/__init__.py +0 -0
  40. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/__init__.py +0 -0
  41. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/assets.py +0 -0
  42. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/color.py +0 -0
  43. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/converter.py +0 -0
  44. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/distort.py +0 -0
  45. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/filter.py +0 -0
  46. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/group.py +0 -0
  47. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/input.py +0 -0
  48. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/interface.py +0 -0
  49. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/manual.py +0 -0
  50. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/matte.py +0 -0
  51. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/output.py +0 -0
  52. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/compositor/vector.py +0 -0
  53. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/__init__.py +0 -0
  54. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/assets.py +0 -0
  55. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/attribute.py +0 -0
  56. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/color.py +0 -0
  57. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/geometry.py +0 -0
  58. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/grid.py +0 -0
  59. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/group.py +0 -0
  60. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/groups.py +0 -0
  61. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/input.py +0 -0
  62. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/interface.py +0 -0
  63. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/output.py +0 -0
  64. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/texture.py +0 -0
  65. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/utilities.py +0 -0
  66. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/geometry/vector.py +0 -0
  67. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/__init__.py +0 -0
  68. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/assets.py +0 -0
  69. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/color.py +0 -0
  70. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/converter.py +0 -0
  71. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/grid.py +0 -0
  72. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/group.py +0 -0
  73. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/input.py +0 -0
  74. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/manual.py +0 -0
  75. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/output.py +0 -0
  76. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/script.py +0 -0
  77. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/shader.py +0 -0
  78. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/texture.py +0 -0
  79. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/nodes/shader/vector.py +0 -0
  80. {nodebpy-520.3.0 → nodebpy-520.5.0}/src/nodebpy/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nodebpy
3
- Version: 520.3.0
3
+ Version: 520.5.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 = "520.3.0"
3
+ version = "520.5.0"
4
4
  description = "Build nodes trees in Blender more elegantly with code"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -42,5 +42,5 @@ dev = [
42
42
  "syrupy>=5.0.0",
43
43
  "pytest-xdist>=3.8.0",
44
44
  "griffe<2.0.0",
45
- "ty>=0.0.35",
45
+ "ty==0.0.51",
46
46
  ]
@@ -144,7 +144,7 @@ def _introspect(library: AssetLibrary, names: set[str] | None) -> list[_AssetCla
144
144
  path = library.path()
145
145
  library_source = _library_source(library)
146
146
 
147
- with bpy.data.libraries.load(path, link=False, assets_only=True) as (src, _):
147
+ with bpy.data.libraries.load(path, link=False, assets_only=True) as (src, _): # ty: ignore[invalid-context-manager]
148
148
  available = list(src.node_groups)
149
149
  wanted = [n for n in available if names is None or n in names]
150
150
 
@@ -155,7 +155,7 @@ def _introspect(library: AssetLibrary, names: set[str] | None) -> list[_AssetCla
155
155
  # compositor "Combine Spherical" both exist) and we'd introspect the
156
156
  # wrong one. Blender renames the appended copy on a clash; that's fine,
157
157
  # we only read its interface (the emitted _asset_name uses the original).
158
- with bpy.data.libraries.load(path, link=False, assets_only=True) as (
158
+ with bpy.data.libraries.load(path, link=False, assets_only=True) as ( # ty: ignore[invalid-context-manager]
159
159
  src,
160
160
  dst,
161
161
  ):
@@ -170,7 +170,7 @@ def _introspect(library: AssetLibrary, names: set[str] | None) -> list[_AssetCla
170
170
  "CompositorNodeTree": "CompositorNodeGroup",
171
171
  }[group.bl_idname]
172
172
  node = host.nodes.new(node_type)
173
- node.node_tree = group
173
+ node.node_tree = group # ty: ignore[unresolved-attribute]
174
174
  classes.append(
175
175
  _AssetClass(
176
176
  class_name=_class_name(name),
@@ -93,7 +93,10 @@ class _AssetGroupMixin:
93
93
  path = cls._library.path()
94
94
  if not os.path.exists(path):
95
95
  raise FileNotFoundError(f"Asset library not found: {path}")
96
- with bpy.data.libraries.load(path, link=False, assets_only=True) as (src, dst):
96
+ with bpy.data.libraries.load(path, link=True, pack=True, assets_only=True) as ( # ty: ignore[invalid-context-manager]
97
+ src,
98
+ dst,
99
+ ):
97
100
  if cls._asset_name not in src.node_groups:
98
101
  raise KeyError(f"Node group {cls._asset_name!r} not found in {path}")
99
102
  dst.node_groups = [cls._asset_name]
@@ -367,7 +367,11 @@ class LinkingMixin:
367
367
  else:
368
368
  self._link(source, input)
369
369
 
370
- def __rshift__(self, other: _RShiftT) -> _RShiftT:
370
+ @overload
371
+ def __rshift__(self, other: None) -> Self: ...
372
+ @overload
373
+ def __rshift__(self, other: _RShiftT) -> _RShiftT: ...
374
+ def __rshift__(self, other: _RShiftT | None) -> _RShiftT | Self:
371
375
  """Chain nodes using >> operator. Links output to input.
372
376
 
373
377
  Usage:
@@ -377,8 +381,14 @@ class LinkingMixin:
377
381
  If the target node has an ellipsis placeholder (...), links to that specific input.
378
382
  Otherwise, finds the best compatible socket pair based on type compatibility.
379
383
 
380
- Returns the right-hand node to enable continued chaining.
384
+ Returns the right-hand node to enable continued chaining. A ``None``
385
+ target is a no-op passthrough — nothing is linked and ``self`` is
386
+ returned so an optional node can be conditionally skipped::
387
+
388
+ src >> SetPosition() >> (Transform() if trans else None) >> out
381
389
  """
390
+ if other is None:
391
+ return self
382
392
  if isinstance(other, _SocketLike):
383
393
  source = self._default_output_socket
384
394
  target = other.socket
@@ -677,7 +677,6 @@ class _AccumulateField(_EvaluateField[_T]):
677
677
  def _accumulate(
678
678
  self, output: Literal["leading", "trailing", "total"], group_index: InputInteger
679
679
  ) -> "_T":
680
-
681
680
  from ..nodes.geometry import AccumulateField
682
681
 
683
682
  node = getattr(
@@ -629,7 +629,7 @@ class TreeBuilder(Generic[_TreeT]):
629
629
  ignore_visibility: bool = False,
630
630
  ):
631
631
  if isinstance(tree, str):
632
- self.tree = bpy.data.node_groups.new(tree, tree_type) # type: ignore[assignment]
632
+ self.tree = bpy.data.node_groups.new(tree, tree_type) # ty: ignore[invalid-assignment]
633
633
  else:
634
634
  self.tree = tree # type: ignore
635
635
 
@@ -507,7 +507,7 @@ def _with_probe_tree(tree_idname: str, fn: Callable[[Any], _T], default: _T) ->
507
507
  try:
508
508
  import bpy
509
509
 
510
- probe_tree = bpy.data.node_groups.new("__nodebpy_codegen_probe__", tree_idname)
510
+ probe_tree = bpy.data.node_groups.new("__nodebpy_codegen_probe__", tree_idname) # ty: ignore[invalid-argument-type]
511
511
  try:
512
512
  return fn(probe_tree)
513
513
  finally:
@@ -453,7 +453,7 @@ def sort_reduced_free_columns(
453
453
 
454
454
  def pos(v: Node | Cluster) -> int:
455
455
  w = non_cluster_descendant(H.free_LT, v) if v.type == Kind.CLUSTER else v
456
- return H.free_col.index(cast(Node, w))
456
+ return H.free_col.index(w)
457
457
 
458
458
  for H in crossing_reduction_graphs:
459
459
  H.reduced_free_col.sort(key=pos)
@@ -82,7 +82,7 @@ class _FormatStringMixin(ItemsMixin):
82
82
  ):
83
83
  super().__init__()
84
84
  key_args = {"Format": format}
85
- key_args.update(self._add_inputs(**(items or {}))) # type: ignore
85
+ key_args.update(self._add_inputs(**(items or {})))
86
86
  self._establish_links(**key_args)
87
87
 
88
88
  @property
@@ -1023,7 +1023,7 @@ class CombineBundle(BaseNode):
1023
1023
  default.
1024
1024
  """
1025
1025
  if isinstance(value, str):
1026
- self.node.bundle_items.new(value, name)
1026
+ self.node.bundle_items.new(value, name) # ty: ignore[invalid-argument-type]
1027
1027
  elif isinstance(value, (BaseNode, Socket, bpy.types.NodeSocket)):
1028
1028
  extend = self.node.inputs[len(self.node.inputs) - 1]
1029
1029
  self.tree.link(self._source_socket(value), extend)
@@ -1034,7 +1034,7 @@ class CombineBundle(BaseNode):
1034
1034
  socket_type = _infer_value_type(value)
1035
1035
  if socket_type is None:
1036
1036
  raise TypeError(f"Unsupported bundle item {name!r}: {value!r}")
1037
- self.node.bundle_items.new(socket_type, name)
1037
+ self.node.bundle_items.new(socket_type, name) # ty: ignore[invalid-argument-type]
1038
1038
  self.node.inputs[name].default_value = value
1039
1039
 
1040
1040
 
@@ -6527,7 +6527,7 @@ class SeparateBundle(BaseNode):
6527
6527
  # name and socket-type string (the inverse of CombineBundle, where the
6528
6528
  # type is inferred from a linked source).
6529
6529
  for name, socket_type in (items or {}).items():
6530
- self.node.bundle_items.new(socket_type, name)
6530
+ self.node.bundle_items.new(socket_type, name) # ty: ignore[invalid-argument-type]
6531
6531
  self._establish_links(Bundle=bundle)
6532
6532
 
6533
6533
 
@@ -684,7 +684,7 @@ class EvaluateClosure(BaseNode):
684
684
  # one unlinked. This mirrors CombineBundle (inputs) / SeparateBundle
685
685
  # (outputs).
686
686
  for name, socket_type in (output_items or {}).items():
687
- self.node.output_items.new(socket_type, name)
687
+ self.node.output_items.new(socket_type, name) # ty: ignore[invalid-argument-type]
688
688
  for name, value in (input_items or {}).items():
689
689
  self._add_input_item(name, value)
690
690
  self.active_input_index = active_input_index
@@ -693,7 +693,7 @@ class EvaluateClosure(BaseNode):
693
693
 
694
694
  def _add_input_item(self, name: str, value: "InputLinkable | str") -> None:
695
695
  if isinstance(value, str):
696
- self.node.input_items.new(value, name)
696
+ self.node.input_items.new(value, name) # ty: ignore[invalid-argument-type]
697
697
  return
698
698
  extend = self.node.inputs[len(self.node.inputs) - 1] # input __extend__
699
699
  self.tree.link(self._source_socket(value), extend)
@@ -1795,7 +1795,7 @@ class FieldToGrid(ItemsMixin, BaseNode, Generic[_T]):
1795
1795
  linkable = {k: v for k, v in items.items() if not _is_default_value(v)}
1796
1796
  defaults = {k: v for k, v in items.items() if _is_default_value(v)}
1797
1797
 
1798
- key_args.update(self._add_inputs(**linkable)) # ty: ignore[no-matching-overload]
1798
+ key_args.update(self._add_inputs(**linkable))
1799
1799
  for name, value in defaults.items():
1800
1800
  socket = self._add_socket(name=name, type="FLOAT")
1801
1801
  if value is not None:
@@ -599,12 +599,12 @@ class ClosureZone(_ZonePair):
599
599
  ``"VECTOR"``, …); the item collection lives on the output node and
600
600
  drives the matching output socket on the input node.
601
601
  """
602
- self.output.node.input_items.new(type, name)
602
+ self.output.node.input_items.new(type, name) # ty: ignore[invalid-argument-type]
603
603
  return _wrap_socket(self.input.node.outputs[-2])
604
604
 
605
605
  def output_item(self, name: str, type: str = "GEOMETRY") -> SocketLinker:
606
606
  """Declare a closure output and return the target to feed with ``>>``."""
607
- self.output.node.output_items.new(type, name)
607
+ self.output.node.output_items.new(type, name) # ty: ignore[invalid-argument-type]
608
608
  return _wrap_socket(self.output.node.inputs[-2])
609
609
 
610
610
  @property
File without changes