comparison sat/tools/trigger.py @ 2562:26edcf3a30eb

core, setup: huge cleaning: - moved directories from src and frontends/src to sat and sat_frontends, which is the recommanded naming convention - move twisted directory to root - removed all hacks from setup.py, and added missing dependencies, it is now clean - use https URL for website in setup.py - removed "Environment :: X11 Applications :: GTK", as wix is deprecated and removed - renamed sat.sh to sat and fixed its installation - added python_requires to specify Python version needed - replaced glib2reactor which use deprecated code by gtk3reactor sat can now be installed directly from virtualenv without using --system-site-packages anymore \o/
author Goffi <goffi@goffi.org>
date Mon, 02 Apr 2018 19:44:50 +0200
parents src/tools/trigger.py@af4a38ebf52a
children 56f94936df1e
comparison
equal deleted inserted replaced
2561:bd30dc3ffe5a 2562:26edcf3a30eb
1 #!/usr/bin/env python2
2 # -*- coding: utf-8 -*-
3
4 # SAT: a jabber client
5 # Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 """Misc usefull classes"""
21
22 from sat.core.i18n import _
23 from sat.core.log import getLogger
24 log = getLogger(__name__)
25
26
27 class TriggerException(Exception):
28 pass
29
30
31 class SkipOtherTriggers(Exception):
32 """ Exception to raise if normal behaviour must be followed instead of following triggers list """
33 pass
34
35
36 class TriggerManager(object):
37 """This class manage triggers: code which interact to change the behaviour of SàT"""
38
39 try: # FIXME: to be removed when a better solution is found
40 MIN_PRIORITY = float('-inf')
41 MAX_PRIORITY = float('+inf')
42 except: # XXX: Pyjamas will bug if you specify ValueError here
43 # Pyjamas uses the JS Float class
44 MIN_PRIORITY = Number.NEGATIVE_INFINITY
45 MAX_PRIORITY = Number.POSITIVE_INFINITY
46
47 def __init__(self):
48 self.__triggers = {}
49
50 def add(self, point_name, callback, priority=0):
51 """Add a trigger to a point
52
53 @param point_name: name of the point when the trigger should be run
54 @param callback: method to call at the trigger point
55 @param priority: callback will be called in priority order, biggest
56 first
57 """
58 if point_name not in self.__triggers:
59 self.__triggers[point_name] = []
60 if priority != 0 and priority in [trigger_tuple[0] for trigger_tuple in self.__triggers[point_name]]:
61 if priority in (self.MIN_PRIORITY, self.MAX_PRIORITY):
62 log.warning(_(u"There is already a bound priority [%s]") % point_name)
63 else:
64 log.debug(_(u"There is already a trigger with the same priority [%s]") % point_name)
65 self.__triggers[point_name].append((priority, callback))
66 self.__triggers[point_name].sort(key=lambda trigger_tuple:
67 trigger_tuple[0], reverse=True)
68
69 def remove(self, point_name, callback):
70 """Remove a trigger from a point
71
72 @param point_name: name of the point when the trigger should be run
73 @param callback: method to remove, must exists in the trigger point
74 """
75 for trigger_tuple in self.__triggers[point_name]:
76 if trigger_tuple[1] == callback:
77 self.__triggers[point_name].remove(trigger_tuple)
78 return
79 raise TriggerException("Trying to remove an unexisting trigger")
80
81 def point(self, point_name, *args, **kwargs):
82 """This put a trigger point
83
84 All the triggers for that point will be run
85 @param point_name: name of the trigger point
86 @return: True if the action must be continued, False else
87 """
88 if point_name not in self.__triggers:
89 return True
90
91 for priority, trigger in self.__triggers[point_name]:
92 try:
93 if not trigger(*args, **kwargs):
94 return False
95 except SkipOtherTriggers:
96 break
97 return True
98
99 def returnPoint(self, point_name, *args, **kwargs):
100 """Like point but trigger must return (continue, return_value)
101
102 All triggers for that point must return a tuple with 2 values:
103 - continue, same as for point, if False action must be finished
104 - return_value: value to return ONLY IF CONTINUE IS FALSE
105 @param point_name: name of the trigger point
106 @return: True if the action must be continued, False else
107 """
108
109 if point_name not in self.__triggers:
110 return True
111
112 for priority, trigger in self.__triggers[point_name]:
113 try:
114 cont, ret_value = trigger(*args, **kwargs)
115 if not cont:
116 return False, ret_value
117 except SkipOtherTriggers:
118 break
119 return True, None