Implement decided resolution of #304

- Remove self for normal callables
- Retain self for methods (of course)
- Add decorator to retrieve self for special callbacks that need it
  (Yes, the example is kinda stupid and would be unnecessary with #300)
This commit is contained in:
enkore 2016-01-27 19:07:59 +01:00
parent 3234897409
commit aed169de4d
2 changed files with 44 additions and 2 deletions

View File

@ -1,3 +1,5 @@
import inspect
from i3pystatus.core.settings import SettingsBase
from i3pystatus.core.threading import Manager
from i3pystatus.core.util import (convert_position,
@ -6,6 +8,14 @@ from i3pystatus.core.command import execute
from i3pystatus.core.command import run_through_shell
def is_method_of(method, object):
"""Decide whether ``method`` is contained within the MRO of ``object``."""
for cls in inspect.getmro(object.__class__):
if method in cls.__dict__.values():
return True
return False
class Module(SettingsBase):
output = None
position = 0
@ -80,8 +90,11 @@ class Module(SettingsBase):
else:
args = []
if callable(cb):
our_method = is_method_of(cb, self)
if callable(cb) and not our_method:
self.__log_button_event(button, cb, args, "Python callback")
cb(*args)
elif our_method:
cb(self, *args)
elif hasattr(self, cb):
if cb is not "run":

View File

@ -3,7 +3,7 @@ import functools
import re
import socket
import string
import inspect
from threading import Timer, RLock
@ -558,3 +558,32 @@ class MultiClickHandler(object):
self.clear_timer()
return ret
def get_module(function):
"""Function decorator for retrieving the ``self`` argument from the stack.
Intended for use with callbacks that need access to a modules variables, for example:
.. code:: python
from i3pystatus import Status
from i3pystatus.core.util import get_module
from i3pystatus.core.command import execute
status = Status(...)
# other modules etc.
@get_module
def display_ip_verbose(module):
execute('sh -c "ip addr show dev {dev} | xmessage -file -"'.format(dev=module.interface))
status.register("network", interface="wlan1", on_leftclick=display_ip_verbose)
"""
@functools.wraps(function)
def call_wrapper(*args, **kwargs):
stack = inspect.stack()
caller_frame_info = stack[1]
self = caller_frame_info[0].f_locals["self"]
# not completly sure whether this is necessary
# see note in Python docs about stack frames
del stack
function(self, *args, **kwargs)
return call_wrapper