Control event order with nested Parameterized

Hi,

I’m trying to adjust the order in which events are executed when I have nested Parameterized objects. The precedence level doesn’t seem to work across different objects, but the order of events in my example does follow a pattern that must be defined somewhere (and so is hopefully adjustable).

The events for the nested objects are always executed in the order in which the objects were created, finally the events from the container class are executed according to precedence.

import param
import numpy as np

class Sub(param.Parameterized):

    data = param.Number(allow_refs=True)

    def __init__(self, **params):
        super().__init__(**params)
        self.precedence = np.random.randint(5, 10)
        self.param.watch(self.data_changed, "data", precedence=self.precedence)

    def data_changed(self, event):
        print(f"[{self.name}]  ({self.precedence})")


class Test(param.Parameterized):

    my_list = param.List(item_type = Sub)

    data = param.Number()

    def __init__(self, **params):
        super().__init__(**params)
        self.param.watch(self.data_changed, "data", precedence=0)
        self.param.watch(self.data_really_changed, "data", precedence=1)

    def make_sub(self):
        sub = Sub(data = self.param["data"])
        self.param.update(
            my_list = self.my_list + [sub]
        )

    def data_changed(self, event):
        print(f"[{self.name}] (0)")

    def data_really_changed(self, event):
        print(f"[{self.name}] (1)")

test = Test()

test.make_sub()
test.make_sub()
test.make_sub()

test.data = 5

Gives e.g.:

[Sub00057]  (6)
[Sub00058]  (8)
[Sub00059]  (5)
[Test00056] (0)
[Test00056] (1)

But I want to first execute the events linked to Test00056 and then the events linked to the Sub000XX instances.

Any ideas on how to do this?

Thanks!

Came up with a solution, it adds a bit of complexity, but seems reasonable:

import param
import numpy as np

class Sub(param.Parameterized):

    data = param.Number(allow_refs=True)
    data_trigger = param.Event(allow_refs=True)

    def __init__(self, precedence, **params):
        super().__init__(**params)
        self.precedence = precedence
        self.param.watch(self.data_changed, ["data_trigger"], precedence=self.precedence)

    def data_changed(self, event):
        print(f"[{self.name}]  ({self.precedence}): data = {self.data}")


class Test(param.Parameterized):

    my_list = param.List(item_type = Sub)

    data = param.Number()
    data_trigger = param.Event()

    def __init__(self, **params):
        super().__init__(**params)

        self.param.watch(self.data_changed, "data", precedence=0)
        self.param.watch(self.data_really_changed, "data", precedence=1)
        self.param.watch(self.trigger_data, "data", precedence=2)

    def make_sub(self):
        sub = Sub(data = self.param["data"],
                  data_trigger = self.param["data_trigger"],
                  precedence=np.random.randint(5, 10))
        self.param.update(
            my_list = self.my_list + [sub]
        )

    def data_changed(self, event):
        print(f"[{self.name}] (0)")

    def data_really_changed(self, event):
        print(f"[{self.name}] (1)")

    def trigger_data(self, event):
        print(f"[{self.name}] (2)")
        self.param.trigger("data_trigger")

test = Test()

test.make_sub()
test.make_sub()
test.make_sub()

test.data = 7

gives e.g.:

[Test00051] (0)
[Test00051] (1)
[Test00051] (2)
[Sub00052]  (9): data = 7
[Sub00053]  (7): data = 7
[Sub00054]  (8): data = 7

For me it seems more like a bug:
If you inspect the watchers, precedence seems to be ignore when the watcher is created in the subclass

ah ok, would definitely prefer to just set the precedences. Should I open a bug report?

Yes, I could be wrong but I think it’s not an intended behavior

Moreover, the precedence of your subclasses is still not respected it should be 7 → 8 → 9

yeah the precedence is only respected within each Parameterized instance, but not across them.