Python: Expose NodeLink.multi_input_socket_index #115249

Closed
Som1Lse wants to merge 2 commits from Som1Lse/blender:main into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
First-time contributor

This exposes NodeLink.multi_input_socket_index as a readonly property,
along with a swap_multi_input_socket_index function that provides a
safe and composable way to change it from Python.

Additionally this property is used in NodeSocket.links to sort the
returned tuple for input sockets.
This fixes a bug in Node Wrangler, where resetting nodes could change
the order of links.

This allows addons to read and reorder inputs to multi socket nodes,
functionality that was previously missing and could only be done from
C++, despite not being an uncommon operation.

This exposes `NodeLink.multi_input_socket_index` as a readonly property, along with a `swap_multi_input_socket_index` function that provides a safe and composable way to change it from Python. Additionally this property is used in `NodeSocket.links` to sort the returned tuple for input sockets. This fixes a bug in Node Wrangler, where resetting nodes could change the order of links. This allows addons to read and reorder inputs to multi socket nodes, functionality that was previously missing and could only be done from C++, despite not being an uncommon operation.
Author
First-time contributor

First pull request, let me know if there is stuff I can improve.

Problem being addressed

Currently addons have no way of knowing the order of links to multi input socket nodes. For most nodes this doesn't matter but for Join Strings, it does. This means any operations that must preserve these cannot correctly be implemented by addons, and must be implemented in C++. Examples of this are Make Group, Duplicate and Node Wrangler's Reset Node.

What I've done

This exposes NodeLink.multi_input_socket_index to addons as a read-only property, and a swap_multi_input_socket_index function that swaps the index with that of another link, which provides a safe and composable interface for reordering links.

It is used by the NodeSocket.links property to sort links for input sockets. This makes the order reliable and meaning for addons, and incidentally fixes Node Wrangler's Reset Node operator, and possibly other addons.

Alternatives considered

Seeing as this solution directly matches the representation of bNodeLink there isn't much room for design space without completely redesigning how links work.

I did consider using shorter names, but I consider this to be an advanced feature, and so I decided to stick with the longer name used in C++.

Limitations

The API is very simple. While operations like move/rotate/sort can be implemented on top of swap in Python, it will not be as efficient as modifying multi_input_socket_index directly.

Things I didn't do

I haven't written any tests for the code, and I didn't look into it. If there is a good example of writing automated tests for the Python API I'll gladly write some.

The documentation is also fairly rudimentary. I would definitely welcome comments here.

First pull request, let me know if there is stuff I can improve. **Problem being addressed** Currently addons have no way of knowing the order of links to multi input socket nodes. For most nodes this doesn't matter but for Join Strings, it does. This means any operations that must preserve these cannot correctly be implemented by addons, and must be implemented in C++. Examples of this are Make Group, Duplicate and Node Wrangler's Reset Node. **What I've done** This exposes `NodeLink.multi_input_socket_index` to addons as a read-only property, and a `swap_multi_input_socket_index` function that swaps the index with that of another link, which provides a safe and composable interface for reordering links. It is used by the `NodeSocket.links` property to sort links for input sockets. This makes the order reliable and meaning for addons, and incidentally fixes Node Wrangler's Reset Node operator, and possibly other addons. **Alternatives considered** Seeing as this solution directly matches the representation of `bNodeLink` there isn't much room for design space without completely redesigning how links work. I did consider using shorter names, but I consider this to be an advanced feature, and so I decided to stick with the longer name used in C++. **Limitations** The API is very simple. While operations like move/rotate/sort can be implemented on top of swap in Python, it will not be as efficient as modifying `multi_input_socket_index` directly. **Things I didn't do** I haven't written any tests for the code, and I didn't look into it. If there is a good example of writing automated tests for the Python API I'll gladly write some. The documentation is also fairly rudimentary. I would definitely welcome comments here.
Iliya Katushenock added this to the Nodes & Physics project 2023-11-22 12:21:21 +01:00
Iliya Katushenock added the
Module
Python API
label 2023-11-22 12:21:25 +01:00
Som1Lse force-pushed main from 09680ce8a3 to 1cb16fba70 2023-11-27 18:52:18 +01:00 Compare
Som1Lse closed this pull request 2023-11-27 18:52:49 +01:00

What's with this PR?

What's with this PR?
Author
First-time contributor

I messed up the commits when I did a force push, so I closed it. There wasn't much interest before so I didn't get around to resubmitting it.

I messed up the commits when I did a force push, so I closed it. There wasn't much interest before so I didn't get around to resubmitting it.
Author
First-time contributor

If there's a way to fix the commit history easily, I'll can do that, otherwise, I'll just open a new PR. I can format it better that way too, since the wiki is actually up now.

If there's a way to fix the commit history easily, I'll can do that, otherwise, I'll just open a new PR. I can format it better that way too, since the wiki is actually up now.

Not sure if there is any issues

Not sure if there is any issues
Iliya Katushenock reopened this pull request 2023-12-13 11:45:37 +01:00
Iliya Katushenock reviewed 2023-12-13 12:11:33 +01:00
@ -1232,0 +1228,4 @@
links = (link for link in self.id_data.links
if self in (link.from_socket, link.to_socket))
if not self.is_output:

If statement should not be necessary, this collection is will have 0/1 sizes in this case.

`If` statement should not be necessary, this collection is will have `0`/`1` sizes in this case.
Author
First-time contributor

Output sockets can always have > 1 links.

The check is there because I don't want to sort links from output by the input sockets they're connected to, as this is really unintuitive.

Here's an example. (Link to image) First AD is created, then AC. A.links is [AD, AC] because AC.multi_input_socket_index == AD.multi_input_socket_index == 0. After moving AD (or inserting a link above it), we have AC.multi_input_socket_index < AD.multi_input_socket_index and A.links becomes [AC, AD].

Output sockets can always have > 1 links. The check is there because I don't want to sort links from output by the input sockets they're connected to, as this is really unintuitive. Here's an example. [(Link to image)](https://imgur.com/a/qYyW9Th) First `AD` is created, then `AC`. `A.links` is `[AD, AC]` because `AC.multi_input_socket_index == AD.multi_input_socket_index == 0`. After moving `AD` (or inserting a link above it), we have `AC.multi_input_socket_index < AD.multi_input_socket_index` and `A.links` becomes `[AC, AD]`.

Ah, multiple output links, yeah..

Ah, multiple output links, yeah..
mod_moder marked this conversation as resolved
Member

Closing in favor of #118987. Thanks for the patch.

Closing in favor of #118987. Thanks for the patch.
Jacques Lucke closed this pull request 2024-03-01 22:34:19 +01:00

Pull request closed

Sign in to join this conversation.
No reviewers
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#115249
No description provided.