2

I'm trying to configure a decorator at run time. This is somewhat related to my earlier question: How to configure a decorator in Python

The motivation for this is that I'm trying to use the Thespian troupe code "as-is".

Is it legal to have this code here, where I've defined the class (and therefore called the decorator) inside a class method? Again, the reason for this is that I could feed the max_count argument prior to the decorator being call.

The module is calculator.calculator (yes, bad choice perhaps)

class Scheduler:
    def __init__(self):
        self.actor_system = None

    def start(self):
        self.actor_system = ActorSystem('multiprocTCPBase')

    def stop(self):
        self.actor_system.shutdown()

    def launch(self, count, func_and_data, status_cb):
        class CalcPayload:
            def __init__(self, func_and_data, status_cb):
                self.func_and_data = func_and_data
                self.status_cb = status_cb

        @troupe(max_count=count)
        class Execute(ActorTypeDispatcher):
            def receiveMsg_CalcPayload(self, msg, sender):
                func = msg.func_and_data['func']
                data = msg.func_and_data['data']
                status_cb = msg.status_cb

                self.send(sender, func(data, status_cb))

        exec_actor = self.actor_system.createActor(Execute)

        for index in range(len(func_and_data)):
            calc_config = CalcPayload(func_and_data[index], status_cb)
            self.actor_system.tell(exec_actor, calc_config)

        for index in range(len(func_and_data)):
            result = self.actor_system.listen(timeout)

        self.actor_system.tell(exec_actor, ActorExitRequest())

For various reasons, I can't apply the decorator to the class when I use it. There is a brief discussion on this in the question I referenced.

Brian
  • 642
  • 7
  • 18

2 Answers2

1

While not invalid, it is generally inadvisable to define a class as a local variable inside a function, as it would make access to the class difficult outside the function.

Instead, you can define the classes outside the function, and apply the decorator function to the class when it's actually needed by calling the decorator function with the class object:

class CalcPayload:
    def __init__(self, func_and_data, status_cb):
        self.func_and_data = func_and_data
        self.status_cb = status_cb


class Execute(ActorTypeDispatcher):
    def receiveMsg_CalcPayload(self, msg, sender):
        func = msg.func_and_data['func']
        data = msg.func_and_data['data']
        status_cb = msg.status_cb

        self.send(sender, func(data, status_cb))

class Scheduler:
    def __init__(self):
        self.actor_system = None

    def start(self):
        self.actor_system = ActorSystem('multiprocTCPBase')

    def stop(self):
        self.actor_system.shutdown()

    def launch(self, count, func_and_data, status_cb):
        exec_actor = self.actor_system.createActor(troupe(max_count=count)(Execute))

        for index in range(len(func_and_data)):
            calc_config = CalcPayload(func_and_data[index], status_cb)
            self.actor_system.tell(exec_actor, calc_config)

        for index in range(len(func_and_data)):
            result = self.actor_system.listen(timeout)

        self.actor_system.tell(exec_actor, ActorExitRequest())
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • My apologies, but I already tried that approach and the library for one reason or another doesn't like that technique to apply the decorator to the function. The decorator just doesn't seem to "work", and the class executes as if it wasn't there. In my original code, I don't really need the class outside of where I'm calling it, but I would also like to do things in a pythonic method, rather than kludging something together. – Brian Apr 15 '19 at 21:43
  • I tried it again, because I think it SHOULD work, and I get this exception: `thespian.actors.InvalidActorSpecification: Invalid Actor Specification: (module 'calculator.calculator' has no attribute 'Execute')`....so it says that the class with a particular definition is not valid, and then it points to the definition. Clearly I'm doing something wrong. – Brian Apr 15 '19 at 21:47
  • 1
    Oh, and for anyone that stumbles across this. The in-line decorator syntax cannot be used with the Thespian troupe because, according to the Thespian author: "the multiproc system base needs to perform the actual creation in a separate process, the creation target must be based on the results of the import and cannot be aware of any additional local computations." – Brian Apr 17 '19 at 15:57
1

The actor_system is going to want to build instances of your class. That means it needs to be able to derive the class object- you cannot define it inside of a method.

If you really need to apply the decorator separately, you maybe could do

def launch(self, count, func_and_data, status_cb):
    wrapped = troupe(max_count=count)(Executor)
    exec_actor = self.actor_system.createActor(wrapped)
Paul Becotte
  • 9,767
  • 3
  • 34
  • 42
  • Thanks Paul. I heard back from the library author that due to the way the multi-processing stuff works (somewhat foreign to me) the in-line method of wrapping a function in a decorator is ignored. I'm back to square one again, but at least I know why now. – Brian Apr 16 '19 at 14:46