Opened 12 years ago

Last modified 11 years ago

#638 accepted enhancement

meta-decorator hooks / emacs-lisp style advice

Reported by: Christopher Allan Webber Owned by:
Priority: minor Milestone:
Component: programming Keywords: pluginapi
Cc: Parent Tickets:

Description (last modified by Christopher Allan Webber)

This is an incredibly evil and flexible idea that, like decorators itself, is probably elegant, hard to understand, powerful, and yes, a little bit evil.

So this is an idea inspired from emacs lisp, which allows you to pass in functions to wrap a function that already exists (this is called "advising functions"). Actually, hooks in emacs look a heck of a lot like decorators, so actually...

Say you have this function:

  @meta_decorator_hook('some_function_hook')
  def some_function(foo):
     bla bla

Now, you want to wrap this function! But how do you wrap it? It's already defined, you can't just wrap arbitrary things around it! ... or can you?

In this meta_decorator_hook, the meta_decorator_hook returns a lazy-loaded method set to actually construct a chain of wrapped methods. So if we did something like:

  pluginapi.wrap_function('some_function_hook', our_function)

.. it would return, basically a WrappedFunction() that, the first time it is executed, walks through all the decorator like methods that have been pushed onto that hook and wraps them in each other. That meta-decorated method is cached, and eventually, executed.

Sounds evil, right? :)

This could be super powerful though. You could do crazy things like double-check the results of a view before returning it, or totally override the view and decide not to call it at all for your plugin, call it both before and after, or set up special-case exception handling for hooks that are called within the function itself.

I'm sure I didn't make that sound any less evil, but I think it'd be really great.

Change History (5)

comment:1 by Christopher Allan Webber, 12 years ago

Type: defectenhancement

These are some extra notes explaining additional rationale for this that I wrote in my email about plugins to the mailing list:

How do we "halt" a function if a plugin needs to tell us to?

Exceptions probably... but how to make this clean?

Okay, let me explain a bit more. Say someone implements a special hook that sets up something special (I'm having a hard time thinking of what) but notices that something is terribly wrong. It needs to immediately halt the execution of the function. A reasonable thing to do is raise an exception. But we don't just want it to show up as a programming error and hit the logs. How to handle it? One of two ways:

We could already be expecting certain types of exceptions to possibly be raised like the following:

  try:
     pluginapi.callable_hook_runall('some_hook', arg, blarg)
  except ExpectingThisException:
     something something
     return Response('oh snap')

Okay, but what if the view designers weren't able to anticipate the kind of issue you have... how to handle this?

The answer is the meta-decorators solution above I think. In your own meta-decorator around the view that calls the hook above, you could set yourself up to catch the exception.

Tricky, but should work! :)

comment:2 by Christopher Allan Webber, 12 years ago

Description: modified (diff)

comment:3 by Christopher Allan Webber, 12 years ago

Owner: set to Christopher Allan Webber
Status: newin_progress

This is moving forward along with some other plugin stuff. Claiming.

comment:4 by Christopher Allan Webber, 12 years ago

Milestone: 0.4.00.4.1

Moving to 0.4.1

comment:5 by Christopher Allan Webber, 11 years ago

Milestone: 0.5.0
Owner: Christopher Allan Webber removed
Priority: majorminor
Status: in_progressaccepted

So actually this hasn't really moved forward and I haven't worked on it recently.

I'm also less convinced it's so needed.... presently. Anyway, un-milestoning it and unclaiming. I might get to it later.

If someone finds a need for this, feel free to bump it up in priority.

Note: See TracTickets for help on using tickets.