Event handler : inherited plugins

Hi all,

As I have several projects using the same code basis I wanted to optimize a bit my plugins in order to avoid having to maintain the same code in different places.
Hence I designed my plugins as Classes and put some inheritance between projects plugins and core plugins.
When I run my tests, everything goes fine.
But when I start my project daemon it crashes on first event because of a failed callback. It shows an IndexError and I guess it is because of the empty stack, but I can’t find a way to handle this (I modified the code so it would try the usual way first, then show an alternative message):

INFO:engine:Loading plugin at /app/package/int/shotgun_event_plugins/current/projects/toto/plugins/actorbundle.py
INFO:engine:Loading plugin at /app/package/int/shotgun_event_plugins/current/projects/toto/plugins/asset.py
INFO:engine:Loading plugin at /app/package/int/shotgun_event_plugins/current/common/plugins/review.py
INFO:engine:Loading plugin at /app/package/int/shotgun_event_plugins/current/common/plugins/timelog.py
INFO:engine:Loading plugin at /app/package/int/shotgun_event_plugins/current/common/plugins/episode.py
INFO:engine:Loading plugin at /app/package/int/shotgun_event_plugins/current/projects/toto/plugins/task.py
INFO:engine:Treating event 13835317
CRITICAL:plugin.task.manage_task:An error occured processing an event.

Traceback (most recent call last):
  File "/app/package/int/shotgun_events/2.0.4/shotgunEvents/src/shotgunEventDaemon.py", line 1488, in process
    self._logger.critical(msg, traceback.format_exc(), pprint.pformat(stack[1].f_locals))
IndexError: list index out of range


Local variables at outer most frame in plugin:

'no local variables'
INFO:timing:event_id=13835317 created_at=2019-07-03T13:10:18+02:00 callback=task.manage_task start=2019-12-11T11:35:34.495531+01:00 end=2019-12-11T11:35:36.279610+01:00 duration=00:00:00:01.784079 error=True delay=160:23:25:16.495531

What puzzles me is that the timing log seems to recognize the callback !
So first question would be: is it ok to use plugins as classes?
Then: are there special tricks to do this?

Best Regards,
Francois

3 Likes

Hi again,

continuing to dig into the stacktrace I exposed what was in stack[0] as I still don’t know really why we use stack[1]. I got this:

CRITICAL:plugin.task.run_callback:An error occured processing an event.

Traceback (most recent call last):
  File "/app_p/package/int/shotgun_events/2.0.5/shotgunEvents/src/shotgunEventDaemon.py", line 1488, in process
    self._logger.critical(msg, traceback.format_exc(), pprint.pformat(stack[1].f_locals))
IndexError: list index out of range


And Local variables are not even available!
Here is the current stack:

{'error': True,
 'event': {'attribute_name': 'sg_status_list',
           'created_at': datetime.datetime(2019, 7, 3, 13, 10, 18, tzinfo=<shotgun_api3.lib.sgtimezone.LocalTimezone object at 0x7f13d63ca290>),
           'entity': {'id': 69540, 'name': 'concept', 'type': 'Task'},
           'event_type': 'Shotgun_Task_Change',
           'id': 13835317,
           'meta': {'attribute_name': 'sg_status_list',
                    'entity_id': 69540,
                    'entity_type': 'Task',
                    'field_data_type': 'status_list',
                    'new_value': 'apr',
                    'old_value': 'cmpt',
                    'type': 'attribute_change'},
           'project': <blanked>,
           'session_uuid': <blanked>,
           'type': 'EventLogEntry',
           'user': <blanked>},
 'msg': 'An error occured processing an event.\n\n%s\n\nAnd Local variables are not even available! \n\nHere is the current stack:\n\n%s',
 'self': <__main__.Callback object at 0x7f13d565c650>,
 'stack': [<frame object at 0x2a48720>],
 'start_time': datetime.datetime(2019, 12, 12, 13, 29, 49, 186069, tzinfo=<shotgun_api3.lib.sgtimezone.LocalTimezone object at 0x7f13d63caad0>),
 'tb': None}

We can see here that:

  1. there is no traceback (tb: None) which is why I get an IndexError. The code before reaching this point is :
            # Get the local variables of the frame of our plugin
            tb = sys.exc_info()[2]
            stack = []
            while tb:
                stack.append(tb.tb_frame)
                tb = tb.tb_next
  1. stack is not empty, which means there are imbricated stacks. I don’t know if it is the usual way.

Anyway it seems that tb = sys.exc_info()[2] is not working properly here.

Best Regards,
Francois

1 Like

I think I found the issue: a combination of bad import path and function signature… my bad :-/
Nevertheless there might be something to do regarding the stack trace on such errors :slight_smile:

Best Regards,
Francois

3 Likes

Hi François,

The code was developed expecting the plugin code to be in a function in the plugin file, I wonder how it being in a Class would change the stack and how it needs to be introspected.

We’d probably need to suggest a clear pattern for class usage and then modify the code to support both a function and the suggested class approach.

Anyway,
I’m happy you figured out the underlying issue given the unhelpful traces.

2 Likes

Hi Patrick,

as for now I am

  1. declaring the class
  2. instantiating it in the registerCallbacks(reg) function, between the event_filter and reg.registerCallback() call
  3. calling the class method that will handle the event in reg.registerCallback(), just like we do usually with a function

This is a simple way to proceed but it seems to work fine.

Best Regards,
Francois

3 Likes