Skip to content

Commit f275567

Browse files
committed
[teisenbe] Use the imp module to import modules.
Also add a simple translator module
1 parent e3b9334 commit f275567

File tree

5 files changed

+118
-23
lines changed

5 files changed

+118
-23
lines changed

plugins/screen_detach.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from plugin import BasePlugin
12
import os
23
import stat
34
import pyinotify

plugins/test.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
from plugin import BasePlugin
2+
13
class Plugin(BasePlugin):
24
def init(self):
5+
self.add_command('plugintest', self.command_plugintest, 'Test command')
6+
self.add_event_handler('message', self.on_message)
37
self.core.information("Plugin loaded")
48

59
def cleanup(self):

plugins/translate.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from plugin import BasePlugin
2+
import urllib.request
3+
from urllib.parse import urlencode
4+
import xhtml
5+
import json
6+
7+
TARGET_LANG = 'en'
8+
9+
def translate(s, target=TARGET_LANG, source=''):
10+
f = urllib.request.urlopen('http://ajax.googleapis.com/ajax/services/language/translate', urlencode({ 'v': '1.0', 'q': s, 'langpair': '%s|%s' % (source, target) }))
11+
response = json.loads(str(f.read(), 'utf-8'))['responseData']
12+
return (response['translatedText'], response['detectedSourceLanguage'])
13+
14+
class Plugin(BasePlugin):
15+
def init(self):
16+
self.add_event_handler('groupchat_message', self.on_groupchat_message)
17+
18+
def on_groupchat_message(self, message):
19+
try:
20+
room_from = message.getMucroom()
21+
if message['type'] == 'error':
22+
return
23+
24+
if room_from == 'poezio@kikoo.louiz.org':
25+
nick_from = message['mucnick']
26+
body = xhtml.get_body_from_message_stanza(message)
27+
room = self.core.get_room_by_name(room_from)
28+
text, lang = translate(body)
29+
if lang != TARGET_LANG:
30+
room.add_message(text, nickname=nick_from)
31+
except Exception as e:
32+
import traceback
33+
self.core.information("Exception in translator! %s" % (traceback.format_exc(),))

src/plugin.py

+11-15
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
1-
import inspect
2-
31
class BasePlugin(object):
42
"""
53
Class that all plugins derive from. Any methods beginning with command_
64
are interpreted as a command and beginning with on_ are interpreted as
75
event handlers
86
"""
97

10-
def __init__(self, core):
8+
def __init__(self, plugin_manager, core):
119
self.core = core
12-
for k, v in inspect.getmembers(self, inspect.ismethod):
13-
if k.startswith('on_'):
14-
core.xmpp.add_event_handler(k[3:], v)
15-
elif k.startswith('command_'):
16-
command = k[len('command_'):]
17-
core.commands[command] = (v, v.__doc__, None)
10+
self.plugin_manager = plugin_manager
1811
self.init()
1912

2013
def init(self):
@@ -24,10 +17,13 @@ def cleanup(self):
2417
pass
2518

2619
def unload(self):
27-
for k, v in inspect.getmembers(self, inspect.ismethod):
28-
if k.startswith('on_'):
29-
self.core.xmpp.del_event_handler(k[3:], v)
30-
elif k.startswith('command_'):
31-
command = k[len('command_'):]
32-
del self.core.commands[command]
3320
self.cleanup()
21+
22+
def add_command(self, name, handler, help, completion=None):
23+
return self.plugin_manager.add_command(self.__module__, name, handler, help, completion)
24+
25+
def add_event_handler(self, event_name, handler):
26+
return self.plugin_manager.add_event_handler(self.__module__, event_name, handler)
27+
28+
def del_event_handler(self, event_name, handler):
29+
return self.plugin_manager.del_event_handler(self.__module__, event_name, handler)

src/plugin_manager.py

+69-8
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,86 @@
1+
import imp
2+
import os
3+
import sys
4+
from config import config
5+
from gettext import gettext as _
6+
7+
plugins_dir = config.get('plugins_dir', '')
8+
plugins_dir = plugins_dir or\
9+
os.path.join(os.environ.get('XDG_DATA_HOME') or\
10+
os.path.join(os.environ.get('HOME'), '.local', 'share'),
11+
'poezio', 'plugins')
12+
try:
13+
os.makedirs(plugins_dir)
14+
except OSError:
15+
pass
16+
17+
sys.path.append(plugins_dir)
18+
119
class PluginManager(object):
220
def __init__(self, core):
321
self.core = core
4-
self.plugins = {}
22+
self.modules = {} # module name -> module object
23+
self.plugins = {} # module name -> plugin object
24+
self.commands = {} # module name -> dict of commands loaded for the module
25+
self.event_handlers = {} # module name -> list of event_name/handler pairs loaded for the module
526

627
def load(self, name):
728
if name in self.plugins:
829
self.plugins[name].unload()
930

1031
try:
11-
code = compile(open(name).read(), name, 'exec')
12-
from plugin import BasePlugin
13-
globals = { 'BasePlugin' : BasePlugin }
14-
exec(code, globals)
15-
self.plugins[name] = globals['Plugin'](self.core)
32+
if name in self.modules:
33+
imp.acquire_lock()
34+
module = imp.reload(self.modules[name])
35+
imp.release_lock()
36+
else:
37+
file, filename, info = imp.find_module(name, [plugins_dir])
38+
imp.acquire_lock()
39+
module = imp.load_module(name, file, filename, info)
40+
imp.release_lock()
1641
except Exception as e:
17-
self.core.information("Could not load plugin: %s" % (e,))
42+
import traceback
43+
self.core.information(_("Could not load plugin: ") + traceback.format_exc())
44+
return
45+
finally:
46+
if imp.lock_held():
47+
imp.release_lock()
48+
49+
self.modules[name] = module
50+
self.commands[name] = {}
51+
self.event_handlers[name] = []
52+
self.plugins[name] = module.Plugin(self, self.core)
1853

1954
def unload(self, name):
2055
if name in self.plugins:
2156
try:
57+
for command in self.commands[name].keys():
58+
del self.core.commands[command]
59+
for event_name, handler in self.event_handlers[name]:
60+
self.core.xmpp.del_event_handler(event_name, handler)
61+
2262
self.plugins[name].unload()
2363
del self.plugins[name]
64+
del self.commands[name]
65+
del self.event_handlers[name]
2466
except Exception as e:
25-
self.core.information("Could not unload plugin (may not be safe to try again): %s" % (e,))
67+
import traceback
68+
self.core.information(_("Could not unload plugin (may not be safe to try again): ") + traceback.format_exc())
69+
70+
def add_command(self, module_name, name, handler, help, completion=None):
71+
if name in self.core.commands:
72+
raise Exception(_("Command '%s' already exists") % (name,))
73+
74+
commands = self.commands[module_name]
75+
commands[name] = (handler, help, completion)
76+
self.core.commands[name] = (handler, help, completion)
77+
78+
def add_event_handler(self, module_name, event_name, handler):
79+
eh = self.event_handlers[module_name]
80+
eh.append((event_name, handler))
81+
self.core.xmpp.add_event_handler(event_name, handler)
82+
83+
def del_event_handler(self, module_name, event_name, handler):
84+
self.core.xmpp.del_event_handler(event_name, handler)
85+
eh = self.event_handlers[module_name]
86+
eh = list(filter(lambda e : e != (event_name, handler), eh))

0 commit comments

Comments
 (0)