0

This is an extension of Dynamically decorate a function inside a class in Python3

@MisterMyagi properly answered my question that you can dynamically decorate a class using this logic:

class MyTaskSequence(TaskSequence):
    pass


def add_sequence(cls, order, path):
    @seq_task(order)
    def sequence(self):
        self.client.get(path)
    sequence.__name__ = "sequence%d" % order
    setattr(cls, sequence.__name__, sequence)

add_sequence(MyTaskSequence, 1, "/devops/")
add_sequence(MyTaskSequence, 2, "/blog/")

My question is: How do you ensure that the function which is generated can be used as standalone function and as a method of the class at the same time?

eg: Static function definition:

class MyTaskSequence(TaskSequence):
    @seq_task(1)
    def sequence1(self):
        self.client.get("/devops/")

    @seq_task(2)
    def sequence2(self):
        self.client.get("/blog/")

pprint(vars(MyTaskSequence))


>>>> 

mappingproxy({'__doc__': None,
              '__module__': 'run-loadtest.index',
              'sequence1': <function start.<locals>.MyTaskSequence.sequence1 at 0x10d759c20>,
              'sequence2': <function start.<locals>.MyTaskSequence.sequence2 at 0x10d759f80>,
              'tasks': [<function start.<locals>.MyTaskSequence.sequence1 at 0x10d759c20>,
                        <function start.<locals>.MyTaskSequence.sequence2 at 0x10d759f80>]})

What I tried:

class MyTaskSequence(TaskSequence):
    pass


def add_sequence(cls, order, path):
    @seq_task(order)
    def sequence(self):
        self.client.get(path)
    sequence.__name__ = "sequence%d" % order
    setattr(cls, sequence.__name__, sequence)

add_sequence(MyTaskSequence, 1, "/devops/")
add_sequence(MyTaskSequence, 2, "/blog/")

pprint(vars(MyTaskSequence))


>>>> 

mappingproxy({'__doc__': None,
              '__module__': 'run-loadtest.index',
              'sequence1': <function start.<locals>.add_sequence.<locals>.sequence at 0x10590bc20>,
              'sequence2': <function start.<locals>.add_sequence.<locals>.sequence at 0x10590bf80>,
              'tasks': []})

Notice that the resulting object is a bit "different".

Now, I understand that this is caused by the library that I am using, but I am currently under the impression that it is basically caused by the fact that the generated "sequence%d" function is just a standalone function and not also a method of the class.

You can check that by comparing the resulting "definition" of the 2 prints:

 'sequence1': <function start.<locals>.MyTaskSequence.sequence1 at 0x10d759c20>,

VERSUS

'sequence1': <function start.<locals>.add_sequence.<locals>.sequence at 0x10590bc20>,

PS: Notice the missing class name in its definition.

Marius Mitrofan
  • 125
  • 1
  • 6
  • What is your question? What your are showing is just the name and module special attribute. Both objects can still be used as both functions and methods (since there is no difference between the two). A method is simply a function on a class looked up through an instance - it does not matter where it was defined. – MisterMiyagi Oct 05 '19 at 11:42
  • I see. Then it's 100% a problem with the library's task decorator that I'm using... I'll see what I can do. Thank you for your help. PS: The library is locustio (https://locust.io) – Marius Mitrofan Oct 05 '19 at 12:23

0 Answers0