nodebpy 0.2.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

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/nodes/zone.py CHANGED
@@ -2,11 +2,10 @@ from abc import ABC, abstractmethod
2
2
  from typing import Literal
3
3
 
4
4
  import bpy
5
- from bpy.types import NodeSocket
6
5
 
7
- from nodebpy.builder import NodeBuilder, SocketLinker
6
+ from nodebpy.builder import DynamicInputsMixin, NodeBuilder, SocketLinker
8
7
 
9
- from .types import (
8
+ from ..types import (
10
9
  LINKABLE,
11
10
  TYPE_INPUT_BOOLEAN,
12
11
  TYPE_INPUT_GEOMETRY,
@@ -16,7 +15,7 @@ from .types import (
16
15
  )
17
16
 
18
17
 
19
- class BaseZone(NodeBuilder, ABC):
18
+ class BaseZone(DynamicInputsMixin, NodeBuilder, ABC):
20
19
  _items_attribute: Literal["state_items", "repeat_items"]
21
20
 
22
21
  @property
@@ -81,30 +80,6 @@ class BaseZoneInput(BaseZone, NodeBuilder, ABC):
81
80
  item = self.items.new(type, name)
82
81
  return self.inputs[item.name]
83
82
 
84
- def __rshift__(self, other):
85
- """Custom zone input linking that creates sockets as needed"""
86
- # Check if target is a zone output without inputs
87
- if (
88
- hasattr(other, "_default_input_socket")
89
- and other._default_input_socket is None
90
- ):
91
- # Target zone needs a socket - create one based on our output
92
- from ..builder import SOCKET_COMPATIBILITY
93
-
94
- source_socket = self._default_output_socket
95
- source_type = source_socket.type
96
-
97
- compatible_types = SOCKET_COMPATIBILITY.get(source_type, [source_type])
98
- best_type = compatible_types[0] if compatible_types else source_type
99
-
100
- # Create socket on target zone
101
- target_socket = other._add_socket(name=best_type.title(), type=best_type)
102
- self.tree.link(source_socket, target_socket)
103
- return other
104
- else:
105
- # Use the general smart linking approach
106
- return self._smart_link_to(other)
107
-
108
83
 
109
84
  class BaseZoneOutput(BaseZone, NodeBuilder, ABC):
110
85
  """Base class for zone output nodes"""
@@ -122,69 +97,22 @@ class BaseZoneOutput(BaseZone, NodeBuilder, ABC):
122
97
  item = self.items.new(type, name)
123
98
  return self.node.inputs[item.name]
124
99
 
125
- def __rshift__(self, other):
126
- """Custom zone output linking that creates sockets as needed"""
127
- from ..builder import SOCKET_COMPATIBILITY
128
-
129
- # Get the source socket type
130
- source_socket = self._default_output_socket
131
- source_type = source_socket.type
132
-
133
- # Check if target has compatible inputs
134
- if hasattr(other, "_default_input_socket") and other._default_input_socket:
135
- # Normal linking
136
- return super().__rshift__(other)
137
- elif hasattr(other, "_add_socket"):
138
- # Target is also a zone - create compatible socket
139
- compatible_types = SOCKET_COMPATIBILITY.get(source_type, [source_type])
140
- best_type = compatible_types[0] if compatible_types else source_type
141
-
142
- # Create socket on target zone
143
- target_socket = other._add_socket(name=best_type.title(), type=best_type)
144
- self.tree.link(source_socket, target_socket)
145
- return other
146
- else:
147
- # Normal NodeBuilder
148
- return super().__rshift__(other)
149
-
150
- @property
151
- def _default_input_socket(self) -> NodeSocket:
152
- """Get default input socket, avoiding skip-type sockets"""
153
- inputs = list(self.inputs.values())
154
- if inputs:
155
- return inputs[0].socket
156
- else:
157
- # No socket exists - this should be handled by zone-specific __rshift__ logic
158
- # Return None to signal that a socket needs to be created
159
- return None
160
-
161
-
162
- class SimulationZone:
163
- def __init__(self, *args: LINKABLE, **kwargs: LINKABLE):
164
- self.input = SimulationInput()
165
- self.output = SimulationOutput()
166
- self.input.node.pair_with_output(self.output.node)
167
-
168
- self.output.node.state_items.clear()
169
- socket_lookup = self.output._add_inputs(*args, **kwargs)
170
- for name, source in socket_lookup.items():
171
- self.input._link_from(source, name)
172
-
173
- def delta_time(self) -> SocketLinker:
174
- return self.input.o_delta_time
175
-
176
- def __getitem__(self, index: int):
177
- match index:
178
- case 0:
179
- return self.input
180
- case 1:
181
- return self.output
182
- case _:
183
- raise IndexError("SimulationZone has only two items")
184
-
185
100
 
186
101
  class BaseSimulationZone(BaseZone):
187
102
  _items_attribute = "state_items"
103
+ _socket_data_types = (
104
+ "VALUE",
105
+ "INT",
106
+ "BOOLEAN",
107
+ "VECTOR",
108
+ "RGBA",
109
+ "ROTATION",
110
+ "MATRIX",
111
+ "STRING",
112
+ "GEOMETRY",
113
+ "BUNDLE",
114
+ )
115
+ _type_map = {"VALUE": "FLOAT"}
188
116
 
189
117
  @property
190
118
  def items(self) -> bpy.types.NodeGeometrySimulationOutputItems:
@@ -194,7 +122,7 @@ class BaseSimulationZone(BaseZone):
194
122
  class SimulationInput(BaseSimulationZone, BaseZoneInput):
195
123
  """Simulation Input node"""
196
124
 
197
- name = "GeometryNodeSimulationInput"
125
+ _bl_idname = "GeometryNodeSimulationInput"
198
126
  node: bpy.types.GeometryNodeSimulationInput
199
127
 
200
128
  @property
@@ -206,7 +134,7 @@ class SimulationInput(BaseSimulationZone, BaseZoneInput):
206
134
  class SimulationOutput(BaseSimulationZone, BaseZoneOutput):
207
135
  """Simulation Output node"""
208
136
 
209
- name = "GeometryNodeSimulationOutput"
137
+ _bl_idname = "GeometryNodeSimulationOutput"
210
138
  node: bpy.types.GeometryNodeSimulationOutput
211
139
 
212
140
  @property
@@ -215,39 +143,49 @@ class SimulationOutput(BaseSimulationZone, BaseZoneOutput):
215
143
  return self._input("Skip")
216
144
 
217
145
 
218
- class RepeatZone:
219
- """Wrapper that supports both direct unpacking and iteration"""
220
-
221
- def __init__(
222
- self, iterations: TYPE_INPUT_INT = 1, *args: LINKABLE, **kwargs: LINKABLE
223
- ):
224
- self.input = RepeatInput(iterations)
225
- self.output = RepeatOutput()
146
+ class SimulationZone:
147
+ def __init__(self, *args: LINKABLE, **kwargs: LINKABLE):
148
+ self.input = SimulationInput()
149
+ self.output = SimulationOutput()
226
150
  self.input.node.pair_with_output(self.output.node)
227
151
 
228
- self.output.node.repeat_items.clear()
229
- self.input._establish_links(**self.input._add_inputs(*args, **kwargs))
230
-
231
- @property
232
- def i(self) -> SocketLinker:
233
- """Input socket: Skip simluation frame"""
234
- return self.input.o_iteration
152
+ self.output.node.state_items.clear()
153
+ socket_lookup = self.output._add_inputs(*args, **kwargs)
154
+ for name, source in socket_lookup.items():
155
+ self.input._link_from(source, name)
235
156
 
236
- def __iter__(self):
237
- """Support for loop: for i, input, output in RepeatZone(...)"""
238
- self._index = 0
239
- return self
157
+ def delta_time(self) -> SocketLinker:
158
+ return self.input.o_delta_time
240
159
 
241
- def __next__(self):
242
- """Support for iteration: next(RepeatZone)"""
243
- if self._index > 0:
244
- raise StopIteration
245
- self._index += 1
246
- return self.i, self.input, self.output
160
+ def __getitem__(self, index: int):
161
+ match index:
162
+ case 0:
163
+ return self.input
164
+ case 1:
165
+ return self.output
166
+ case _:
167
+ raise IndexError("SimulationZone has only two items")
247
168
 
248
169
 
249
170
  class BaseRepeatZone(BaseZone):
250
171
  _items_attribute = "repeat_items"
172
+ _socket_data_types = (
173
+ "FLOAT",
174
+ "INT",
175
+ "BOOLEAN",
176
+ "VECTOR",
177
+ "RGBA",
178
+ "ROTATION",
179
+ "MATRIX",
180
+ "STRING",
181
+ "OBJECT",
182
+ "IMAGE",
183
+ "GEOMETRY",
184
+ "COLLECTION",
185
+ "MATERIAL",
186
+ "BUNDLE",
187
+ "CLOSURE",
188
+ )
251
189
 
252
190
  @property
253
191
  def items(self) -> bpy.types.NodeGeometryRepeatOutputItems:
@@ -257,7 +195,7 @@ class BaseRepeatZone(BaseZone):
257
195
  class RepeatInput(BaseRepeatZone, BaseZoneInput):
258
196
  """Repeat Input node"""
259
197
 
260
- name = "GeometryNodeRepeatInput"
198
+ _bl_idname = "GeometryNodeRepeatInput"
261
199
  node: bpy.types.GeometryNodeRepeatInput
262
200
 
263
201
  def __init__(self, iterations: TYPE_INPUT_INT = 1):
@@ -280,14 +218,45 @@ class RepeatInput(BaseRepeatZone, BaseZoneInput):
280
218
  class RepeatOutput(BaseRepeatZone, BaseZoneOutput):
281
219
  """Repeat Output node"""
282
220
 
283
- name = "GeometryNodeRepeatOutput"
221
+ _bl_idname = "GeometryNodeRepeatOutput"
284
222
  node: bpy.types.GeometryNodeRepeatOutput
285
223
 
286
224
 
225
+ class RepeatZone:
226
+ """Wrapper that supports both direct unpacking and iteration"""
227
+
228
+ def __init__(
229
+ self, iterations: TYPE_INPUT_INT = 1, *args: LINKABLE, **kwargs: LINKABLE
230
+ ):
231
+ self.input = RepeatInput(iterations)
232
+ self.output = RepeatOutput()
233
+ self.input.node.pair_with_output(self.output.node)
234
+
235
+ self.output.node.repeat_items.clear()
236
+ self.input._establish_links(**self.input._add_inputs(*args, **kwargs))
237
+
238
+ @property
239
+ def i(self) -> SocketLinker:
240
+ """Input socket: Skip simluation frame"""
241
+ return self.input.o_iteration
242
+
243
+ def __iter__(self):
244
+ """Support for loop: for i, input, output in RepeatZone(...)"""
245
+ self._index = 0
246
+ return self
247
+
248
+ def __next__(self):
249
+ """Support for iteration: next(RepeatZone)"""
250
+ if self._index > 0:
251
+ raise StopIteration
252
+ self._index += 1
253
+ return self.i, self.input, self.output
254
+
255
+
287
256
  class ForEachGeometryElementInput(NodeBuilder):
288
257
  """For Each Geometry Element Input node"""
289
258
 
290
- name = "GeometryNodeForeachGeometryElementInput"
259
+ _bl_idname = "GeometryNodeForeachGeometryElementInput"
291
260
  node: bpy.types.GeometryNodeForeachGeometryElementInput
292
261
 
293
262
  def __init__(
@@ -332,7 +301,7 @@ class ForEachGeometryElementInput(NodeBuilder):
332
301
  class ForEachGeometryElementOutput(NodeBuilder):
333
302
  """For Each Geometry Element Output node"""
334
303
 
335
- name = "GeometryNodeForeachGeometryElementOutput"
304
+ _bl_idname = "GeometryNodeForeachGeometryElementOutput"
336
305
  node: bpy.types.GeometryNodeForeachGeometryElementOutput
337
306
 
338
307
  def __init__(
@@ -6,6 +6,8 @@ from typing import Literal
6
6
  from bpy.types import (
7
7
  NodeSocket,
8
8
  NodeSocketBool,
9
+ NodeSocketBundle,
10
+ NodeSocketClosure,
9
11
  NodeSocketCollection,
10
12
  NodeSocketColor,
11
13
  NodeSocketFloat,
@@ -22,7 +24,7 @@ from bpy.types import (
22
24
  from mathutils import Euler
23
25
 
24
26
  if typing.TYPE_CHECKING:
25
- from ..builder import NodeBuilder, SocketLinker
27
+ from .builder import NodeBuilder, SocketLinker
26
28
 
27
29
 
28
30
  def _is_default_value(value: TYPE_INPUT_ALL):
@@ -67,6 +69,17 @@ TYPE_INPUT_GRID = typing.Union[
67
69
  TYPE_INPUT_VALUE, TYPE_INPUT_VECTOR, TYPE_INPUT_BOOLEAN, TYPE_INPUT_INT
68
70
  ]
69
71
  TYPE_INPUT_MENU = typing.Union[LINKABLE, NodeSocketMenu]
72
+ TYPE_INPUT_BUNDLE = typing.Union[LINKABLE, NodeSocketBundle]
73
+ TYPE_INPUT_CLOSURE = typing.Union[LINKABLE, NodeSocketClosure]
74
+
75
+ TYPE_INPUT_DATA = typing.Union[
76
+ TYPE_INPUT_VALUE,
77
+ TYPE_INPUT_INT,
78
+ TYPE_INPUT_BOOLEAN,
79
+ TYPE_INPUT_VECTOR,
80
+ TYPE_INPUT_ROTATION,
81
+ TYPE_INPUT_MATRIX,
82
+ ]
70
83
 
71
84
  TYPE_INPUT_ALL = typing.Union[
72
85
  TYPE_INPUT_VALUE,
@@ -267,7 +280,7 @@ SOCKET_TYPES = Literal[
267
280
  "CLOSURE",
268
281
  ]
269
282
 
270
- SOCKET_COMPATIBILITY = {
283
+ SOCKET_COMPATIBILITY: dict[str, tuple[str]] = {
271
284
  "VALUE": (
272
285
  "VALUE",
273
286
  "VECTOR",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nodebpy
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Build nodes in Blender with code
5
5
  Author: Brady Johnston
6
6
  Author-email: Brady Johnston <brady.johnston@me.com>
@@ -76,7 +76,7 @@ with TreeBuilder("AnotherTree") as tree:
76
76
 
77
77
  _ = (
78
78
  count
79
- >> n.Points(position=n.RandomValue.vector(min=(-1, -1, -1)))
79
+ >> n.Points(position=n.RandomValue.vector(min=-1))
80
80
  >> n.InstanceOnPoints(instance=n.Cube(), rotation=rotation)
81
81
  >> n.SetPosition(
82
82
  position=n.Position() * 2.0 + (0, 0.2, 0.3),
@@ -94,8 +94,8 @@ tree
94
94
  graph LR
95
95
  N0("NodeGroupInput"):::default-node
96
96
  N1("RandomValue<br/><small>(-1,-1,-1) seed:2</small>"):::converter-node
97
- N2("RandomValue<br/><small>(-1,-1,-1) seed:1</small>"):::converter-node
98
- N3("AlignRotationToVector<br/><small>(0,0,1)</small>"):::converter-node
97
+ N2("RandomValue<br/><small>(-1,-1,-1)</small>"):::converter-node
98
+ N3("AlignRotationToVector"):::converter-node
99
99
  N4("AxisAngleToRotation<br/><small>(0,0,1)</small>"):::converter-node
100
100
  N5("InputPosition"):::input-node
101
101
  N6("Points"):::geometry-node
@@ -109,7 +109,7 @@ graph LR
109
109
  N14("RealizeInstances"):::geometry-node
110
110
  N15("InstanceOnPoints"):::geometry-node
111
111
  N16("NodeGroupOutput"):::default-node
112
- N1 -->|"Value>>Rotation"| N3
112
+ N1 -->|"Value>>Vector"| N3
113
113
  N4 -->|"Rotation>>Rotate By"| N8
114
114
  N3 -->|"Rotation>>Rotation"| N8
115
115
  N2 -->|"Value>>Position"| N6
@@ -0,0 +1,26 @@
1
+ nodebpy/__init__.py,sha256=AcXaVEPnvX1BlraPSSQ-0NR-Ip6cI0WNRqz84xvrTok,285
2
+ nodebpy/arrange.py,sha256=xBHf-lYlvr-BCdI0gHhEn1ETWjEQyYmzgmhIZ1RYal8,11020
3
+ nodebpy/builder.py,sha256=FI-cwNb2XN41L5TiajL4wuaenow4pK8iN6YM9LA6lE8,40838
4
+ nodebpy/nodes/__init__.py,sha256=OKVeUcCUjhmqsEsGKhgkCVe0iq2dWEqJCgcogx9RShM,12528
5
+ nodebpy/nodes/attribute.py,sha256=hme17msRejaqGHKDwvauHdCKMq7OLZhhi1Ax9Oxb7Wo,15043
6
+ nodebpy/nodes/color.py,sha256=ye1LkcJuebjMlJ8OUlKepSOe8-dhImgoL1uXFG1NamE,1652
7
+ nodebpy/nodes/converter.py,sha256=rzp3LmQ8uiDW1sDZg9x-LWkphBFzUn9dCgzETPI5Cdc,99014
8
+ nodebpy/nodes/experimental.py,sha256=Gxd2lKD5Hr4ClSmFojeZpZQr5AapQebDgTeO9R6EqxE,9561
9
+ nodebpy/nodes/geometry.py,sha256=C1H9JIGtzmzbJY7rsEf8c9PkX6Ja0JUKRcAI6uLS-l4,177510
10
+ nodebpy/nodes/grid.py,sha256=Px92tPr9w-_IWdAzaMMaIbVeRAHWFTQF3QJ1FYPMqGc,50345
11
+ nodebpy/nodes/group.py,sha256=PzQ20PrzgtqgQ2XRU7K1pqA9mW5wyt54bUIaqHjdqD0,289
12
+ nodebpy/nodes/input.py,sha256=i4CmSe4mBxlIru-BnzwUH1C_95Op5JpIMd-QiZY-FWE,60082
13
+ nodebpy/nodes/interface.py,sha256=jobDdF_DpioS25-RfnyPLiKcA40ZfwNhOjdLATBHdDk,14947
14
+ nodebpy/nodes/manual.py,sha256=5mICg44VjyJzvBpWnbB83gOGo-7pUC2wZopztEHE4Rw,60499
15
+ nodebpy/nodes/output.py,sha256=py1SgNLQfwTG31KQCHFZn6lC5qg8NixMAoJ1KhnT7XQ,2138
16
+ nodebpy/nodes/texture.py,sha256=JyjsE8WrVJ4wpx3xO6uaJ5A8ll7N6FtWBQs0comAD7s,25526
17
+ nodebpy/nodes/vector.py,sha256=ULEOGx71OCD1Rz2egzkz5RhaKc5huC-LUjghovrnPbQ,15283
18
+ nodebpy/nodes/zone.py,sha256=koY2AnFsbcoReNEa2DdkUnUy2licxgKbUVE5fc0YnJI,11591
19
+ nodebpy/screenshot.py,sha256=gXAwGfeK05YL9XIpghv5nQ5cXVgtR35wnLnTVDAh08g,18885
20
+ nodebpy/screenshot_subprocess.py,sha256=bmuyjedROCasEDI-JdjXWVsYoEX5I-asE3KxMVR30qM,15364
21
+ nodebpy/sockets.py,sha256=eU3p0IdCkYQeVRp8XkkDuOR38JTIzniTXKhsXQgx29Q,1011
22
+ nodebpy/types.py,sha256=DtvTONY-gyTSRnrLCH5b5FuwaQa1Gy9wmMIvY3Oj8DU,10871
23
+ nodebpy-0.3.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
24
+ nodebpy-0.3.0.dist-info/entry_points.txt,sha256=XvODbWiwSnneYWIYjxFJZmXdntQnapg59Ye2LtCKEN4,42
25
+ nodebpy-0.3.0.dist-info/METADATA,sha256=V_RKbjLiA6eO3BUG7tjC2ZzoVzzqttGtCYNkRcaHlN0,6253
26
+ nodebpy-0.3.0.dist-info/RECORD,,
nodebpy/nodes/mesh.py DELETED
@@ -1,17 +0,0 @@
1
- """
2
- Auto-generated Blender Geometry Node classes.
3
-
4
- DO NOT EDIT THIS FILE MANUALLY.
5
- This file is generated by molecularnodes/nodes/generator.py
6
-
7
- To regenerate: Run generator.py from within Blender
8
-
9
- KNOWN LIMITATIONS:
10
- - Dynamic multi-input/output sockets are not yet supported
11
- (these are the unnamed sockets that appear in the UI for nodes like
12
- "Evaluate Closure", "Join Geometry", etc. that allow dragging in
13
- multiple connections)
14
- - TODO: Add support for dynamic socket creation
15
- """
16
-
17
- from __future__ import annotations
@@ -1,25 +0,0 @@
1
- nodebpy/__init__.py,sha256=AcXaVEPnvX1BlraPSSQ-0NR-Ip6cI0WNRqz84xvrTok,285
2
- nodebpy/arrange.py,sha256=xBHf-lYlvr-BCdI0gHhEn1ETWjEQyYmzgmhIZ1RYal8,11020
3
- nodebpy/builder.py,sha256=Wfi4qvrOmdNbKNnOuYVhLMzf6rspvBQnY8eAk4QH3sU,52351
4
- nodebpy/nodes/__init__.py,sha256=vRXLnYtOJK-nAsrNJDT5MGjWnLMawvGDn7HmjQx_YU0,12145
5
- nodebpy/nodes/attribute.py,sha256=ACgOqgZ6PX14NmQVL3Tx67-T4fJUJLVQz9xxGcdSB2Q,13027
6
- nodebpy/nodes/color.py,sha256=xZIbLvYquroHk3N9lTrVNaz8xv8MhE65s4zKTl10qXU,1842
7
- nodebpy/nodes/converter.py,sha256=UEpcVe1APLnXu64CSUZzz2OXvpxgtnUEjov623DkFHU,132396
8
- nodebpy/nodes/experimental.py,sha256=FWyVI6P-NP_vo8JUMBm-pS57naaE4kMqEQUzoOwAkM8,6739
9
- nodebpy/nodes/geometry.py,sha256=81vXjoZdG2vq4cjrxv21nglJ3UUrLAxfN006Bk7uAp4,160537
10
- nodebpy/nodes/grid.py,sha256=mgyEAutS7yfEv2K6zE48hUk7Yg1eBrUW4nGdqrhItfA,34164
11
- nodebpy/nodes/group.py,sha256=HzSTRBZbtRUGKI3vTbRndsxhXVKYIsX0tQfVQ5690G4,512
12
- nodebpy/nodes/input.py,sha256=kofvhhz2bH3cjnHPBjN3w2t-sMUqfmkKPzhXJZFv7vQ,57283
13
- nodebpy/nodes/interface.py,sha256=xSIo8qb8vN58rs71b2sAKIK6jKujWPIaM_eXNgLnIPc,11117
14
- nodebpy/nodes/mesh.py,sha256=B_cX264fFMax0M9xjGQiQcAuHoORj1cAjMmOQilapBw,524
15
- nodebpy/nodes/texture.py,sha256=8Plz7nzZtKGcPyrRlIpyOl_LNwtz5jezdbA8h7IVBHk,2059
16
- nodebpy/nodes/types.py,sha256=Y768eltOU5mMQt4tNT6sjnK2o9VEK0FXn7eeu3G6lb4,10508
17
- nodebpy/nodes/vector.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- nodebpy/nodes/zone.py,sha256=P-xNY0v-8AwU9KgULE1EBvhI27ayFj7qqLWwb4TD8Ik,13506
19
- nodebpy/screenshot.py,sha256=gXAwGfeK05YL9XIpghv5nQ5cXVgtR35wnLnTVDAh08g,18885
20
- nodebpy/screenshot_subprocess.py,sha256=bmuyjedROCasEDI-JdjXWVsYoEX5I-asE3KxMVR30qM,15364
21
- nodebpy/sockets.py,sha256=eU3p0IdCkYQeVRp8XkkDuOR38JTIzniTXKhsXQgx29Q,1011
22
- nodebpy-0.2.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
23
- nodebpy-0.2.0.dist-info/entry_points.txt,sha256=XvODbWiwSnneYWIYjxFJZmXdntQnapg59Ye2LtCKEN4,42
24
- nodebpy-0.2.0.dist-info/METADATA,sha256=PS4WASNyB2eY3_iU9lkm72NqWeuBEBcO1eK2Yl5Iv14,6299
25
- nodebpy-0.2.0.dist-info/RECORD,,