Skip to content
This repository was archived by the owner on Sep 20, 2024. It is now read-only.

Chore: Event callbacks can have order#6080

Merged
iLLiCiTiT merged 21 commits intodevelopfrom
enhancement/event-callbacks-can-have-order
Jan 4, 2024
Merged

Chore: Event callbacks can have order#6080
iLLiCiTiT merged 21 commits intodevelopfrom
enhancement/event-callbacks-can-have-order

Conversation

@iLLiCiTiT
Copy link
Copy Markdown
Member

@iLLiCiTiT iLLiCiTiT commented Dec 20, 2023

Changelog Description

Event callbacks can have order in which are called, and fixed issue with getting function name and file when using partial function as callback.

Additional info

The original idea came from https://github.com/ynput/OpenPype/pull/5830/files#diff-8ac00fa37b696103daef385811bac7aa3d6bb25a55e7fac15dbf5a801b69764aR453 by @BigRoy. It was modified to have the option to define order in existing event system classes.
Difference from that PR is that callbacks are not stored by order in a dictionary, but are stored in a list, and order is an attribute of callback. Callbacks are sorted on each event emit.

I did some speed tests and didn't notice any difference in different approaches of handling the order, all of them were almost identical (even previous implementation is almost matching the speed of current implementation).

Testing notes:

  1. Prepare 2 functions each printing a value.
  2. Create EventSystem or QueuedEventSystem.
  3. Register functions as for the same topic in the event system, but with different order.
  4. Trigger the topic.
from openpype.lib.events import QueuedEventSystem

# Function callbacks
def function_a():
    print("a")

def function_b():
    print("b")

# Without order
event_system = QueuedEventSystem()
event_system.add_callback("test", function_a)
event_system.add_callback("test", function_b)
event_system.emit("test", {}, "test")
>>> a
>>> b

# Add callbacks the same way but define their order
event_system = QueuedEventSystem()
event_system.add_callback("test", function_a, 10)
event_system.add_callback("test", function_b, 0)
event_system.emit("test", {}, "test")
>>> b
>>> a

@ynbot ynbot added size/XS Denotes a PR changes 0-99 lines, ignoring general files type: enhancement Enhancements to existing functionality labels Dec 20, 2023
@iLLiCiTiT iLLiCiTiT requested a review from BigRoy December 20, 2023 17:13
@iLLiCiTiT iLLiCiTiT requested a review from antirotor December 20, 2023 17:14
Copy link
Copy Markdown
Collaborator

@BigRoy BigRoy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks clean, really nice and clear. Nice work!

I do wonder whether it's time to add a pytests for this.

The tests would need to assert that:

  • The callbacks run in the order they were registered (if no order specificied)
  • That ordering works fine when mixed with unordered (which is default order 0)
  • That the event system works without errors with partial functions

Something along the lines of:

from functools import partial
from openpype.lib.events import QueuedEventSystem


def test_unordered_events():
    """
    Test if pyblish filter can filter and modify plugins on-the-fly.
    """
    
    result = []
    
    def function_a():
        result.append("A")
    
    def function_b():
        result.append("B")
    
    def function_c():
        result.append("C")
        
    # Without order
    event_system = QueuedEventSystem()
    event_system.add_callback("test", function_a)
    event_system.add_callback("test", function_b)
    event_system.add_callback("test", function_c)
    event_system.emit("test", {}, "test")
    
    assert result == ["A", "B", "C"]


def test_ordered_events():
    result = []
    
    def function_a():
        result.append("A")
    
    def function_b():
        result.append("B")
    
    def function_c():
        result.append("C")
    
    def function_d():
        result.append("D")
    
    def function_e():
        result.append("E")
    
    def function_f():
        result.append("F")
        
    # Without order
    event_system = QueuedEventSystem()
    event_system.add_callback("test", function_a)
    event_system.add_callback("test", function_b, order=-10)
    event_system.add_callback("test", function_c, order=10)
    event_system.add_callback("test", function_d, order=5)
    event_system.add_callback("test", function_e)
    event_system.add_callback("test", function_f, order=10)
    event_system.emit("test", {}, "test")
    
    assert result == ["B", "A", "E", "D", "C", "F"]


def test_events_partial_callbacks():
    result = []
    
    def function(name):
        result.append(name)
    
    def function_regular():
        result.append("regular")
        
    event_system.add_callback("test", partial(function, "foo"))
    event_system.add_callback("test", function_regular)
    event_system.add_callback("test", partial(function, "bar"))
    event_system.emit("test", {}, "test")
    
    assert result == ["foo", "regular", "bar"]

Note that I didn't test this PR, sorry - lack of time!

@iLLiCiTiT
Copy link
Copy Markdown
Member Author

I do wonder whether it's time to add a pytests for this.

Will add when I have time. Not merging now as the feature is not "must have".

@BigRoy
Copy link
Copy Markdown
Collaborator

BigRoy commented Dec 21, 2023

I do wonder whether it's time to add a pytests for this.

Will add when I have time. Not merging now as the feature is not "must have".

I understand - however, I'll hold of working on this PR #5830 until this is merged I suppose - to move it to this event system?

@iLLiCiTiT
Copy link
Copy Markdown
Member Author

iLLiCiTiT commented Dec 22, 2023

Partial are still not working, will be in next PR. Meaning they still have to be kept in memory somewhere.

@BigRoy
Copy link
Copy Markdown
Collaborator

BigRoy commented Dec 22, 2023

Partial are still not working, will be in next PR. Meaning they still have to be kept in memory somewhere.

If you want - I can also take a look at this PR's branch and try to implement a fix. Thoughts?

@iLLiCiTiT
Copy link
Copy Markdown
Member Author

If you want - I can also take a look at this PR's branch and try to implement a fix. Thoughts?

I have it implemented, but that needs more testing and I would like to merge this.

@BigRoy
Copy link
Copy Markdown
Collaborator

BigRoy commented Dec 22, 2023

Sounds good to me - looking forward to the other PR then.

@iLLiCiTiT
Copy link
Copy Markdown
Member Author

Did some testing and it looks like it works, so I've added it to this PR.

Comment thread tests/unit/openpype/lib/test_event_system.py
Comment thread openpype/lib/events.py Outdated
Comment thread openpype/lib/events.py Outdated
@antirotor
Copy link
Copy Markdown
Member

One note, if you combine callbacks with and without orders, those without should imho run last?

@BigRoy
Copy link
Copy Markdown
Collaborator

BigRoy commented Jan 3, 2024

One note, if you combine callbacks with and without orders, those without should imho run last?

Currently they run at order 0.
Note that you can also register callbacks at orders lower than zero just fine.

So if you want to run before unordered, then register at a negative order.
If you want to run after, register above zero.

Comment thread openpype/lib/events.py Outdated
Comment thread openpype/lib/events.py Outdated
Comment thread openpype/lib/events.py Outdated
Comment thread openpype/lib/events.py Outdated
Comment thread tests/unit/openpype/lib/test_event_system.py
Comment thread openpype/lib/events.py Outdated
Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com>
@iLLiCiTiT iLLiCiTiT merged commit aa9dbf6 into develop Jan 4, 2024
@iLLiCiTiT iLLiCiTiT deleted the enhancement/event-callbacks-can-have-order branch January 4, 2024 09:51
@ynbot ynbot added this to the next-patch milestone Jan 4, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

community contribution size/XS Denotes a PR changes 0-99 lines, ignoring general files target: AYON target: OpenPype type: enhancement Enhancements to existing functionality

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants