|
2 | 2 |
|
3 | 3 | """Provides a base class for registering commands and filters.""" |
4 | 4 |
|
5 | | -# ============================================================================= |
6 | | -# >> IMPORTS |
7 | | -# ============================================================================= |
8 | | -# Source.Python Imports |
9 | | -# Commands |
10 | | -from commands import CommandReturn |
11 | | -# Hooks |
12 | | -from hooks.exceptions import except_hooks |
13 | | - |
14 | 5 |
|
15 | 6 | # ============================================================================= |
16 | 7 | # >> CLASSES |
17 | 8 | # ============================================================================= |
18 | | -class _BaseCommandManager(dict): |
| 9 | +class _BaseCommandManager(object): |
19 | 10 |
|
20 | 11 | """Class used to (un)register commands.""" |
21 | 12 |
|
22 | | - # Store the base attributes |
23 | | - _use_args = True |
24 | | - _callback_manager = None |
| 13 | + # Can be set to a class that acts like a proxy for commands. It will be |
| 14 | + # registered instead of a callback. If the command was issued, the |
| 15 | + # callback manager will be called and it's its responsibility to call the |
| 16 | + # actual callback. |
| 17 | + _callback_proxy = None |
25 | 18 |
|
26 | | - def register_commands(self, names, callback, *args, **kwargs): |
27 | | - """Register the given commands to the given callback.""" |
| 19 | + def __init__(self): |
| 20 | + """Initialize the command manager.""" |
| 21 | + # This will store all created callback proxies |
| 22 | + self._callback_proxies = [] |
| 23 | + |
| 24 | + def _prepare_command_names(self, names): |
| 25 | + """Validate and prepare the given command names. |
| 26 | +
|
| 27 | + The given argument can be a string, list or tuple. A TypeError is |
| 28 | + raised if it does not meet the requirements. |
| 29 | + """ |
28 | 30 | # Was a single command name given? |
29 | 31 | if isinstance(names, str): |
30 | | - |
31 | | - # Store the command as a list |
32 | 32 | names = [names] |
33 | 33 |
|
34 | 34 | # Are the names of a proper iterable type? |
35 | 35 | if not isinstance(names, (list, tuple)): |
36 | | - |
37 | | - # Raise an error |
38 | 36 | raise TypeError( |
39 | 37 | '{0} commands must be passed as a list, tuple, or string,' |
40 | 38 | ' not "{1}"'.format(type(self).__name__, type(names).__name__)) |
41 | 39 |
|
42 | | - # Is there a specified callback manager for this class? |
43 | | - if self._callback_manager is not None: |
44 | | - |
45 | | - # Get the callback manager's instance for the given callback |
46 | | - callback = self._callback_manager(callback, *args, **kwargs) |
47 | | - |
48 | | - # Loop through the given names |
49 | | - for name in names: |
| 40 | + return names |
50 | 41 |
|
51 | | - # Is the command already registered? |
52 | | - if name not in self: |
| 42 | + def _get_command_proxy(self, callback): |
| 43 | + """Return the command proxy for the given callback. |
53 | 44 |
|
54 | | - # Are the arguments supposed to be used |
55 | | - # when getting the command instance? |
56 | | - if self._use_args: |
| 45 | + Raise a ValueError when the proxy wasn't found.""" |
| 46 | + for proxy in self._callback_proxies: |
| 47 | + if proxy.callback is callback: |
| 48 | + return proxy |
57 | 49 |
|
58 | | - # Get the command using the arguments |
59 | | - command = self._get_command(name, *args) |
| 50 | + raise ValueError('Unable to find a proxy for the given callback.') |
60 | 51 |
|
61 | | - # Are the arguments not supposed to be used? |
62 | | - else: |
63 | | - |
64 | | - # Get the command without the arguments |
65 | | - command = self._get_command(name) |
| 52 | + def register_commands(self, names, callback, *args, **kwargs): |
| 53 | + """Register the given commands to the given callback.""" |
| 54 | + names = self._prepare_command_names(names) |
66 | 55 |
|
67 | | - # Add the command to the dictionary |
68 | | - self[name] = _CallbackList(command) |
| 56 | + if self._callback_proxy is not None: |
| 57 | + # Create a new callback proxy for this callback |
| 58 | + callback = self._callback_proxy(callback, *args, **kwargs) |
| 59 | + self._callback_proxies.append(callback) |
69 | 60 |
|
70 | | - # Add the callback to the command's list of callbacks |
71 | | - self[name].append(callback) |
| 61 | + # Register all command names |
| 62 | + for name in names: |
| 63 | + self._get_command(name, *args).add_callback(callback) |
72 | 64 |
|
73 | 65 | def unregister_commands(self, names, callback): |
74 | 66 | """Unregister the given commands from the given callback.""" |
75 | | - # Was a single command name given? |
76 | | - if isinstance(names, str): |
77 | | - |
78 | | - # Store the command as a list |
79 | | - names = [names] |
80 | | - |
81 | | - # Are the names of a proper iterable type? |
82 | | - if not isinstance(names, (list, tuple)): |
| 67 | + names = self._prepare_command_names(names) |
83 | 68 |
|
84 | | - # Raise an error |
85 | | - raise TypeError( |
86 | | - '{0} commands must be passed as a list, tuple, or string,' |
87 | | - ' not "{1}"'.format(type(self).__name__, type(names).__name__)) |
| 69 | + if self._callback_proxy is not None: |
| 70 | + callback = self._get_command_proxy(callback) |
| 71 | + self._callback_proxies.remove(callback) |
88 | 72 |
|
89 | | - # Loop through all given names |
| 73 | + # Unregister all command names |
90 | 74 | for name in names: |
91 | | - |
92 | | - # Is the command registered? |
93 | | - if name not in self: |
94 | | - |
95 | | - # Raise an error |
96 | | - raise KeyError('Command "{0}" not registered'.format(name)) |
97 | | - |
98 | | - # Is there a specified callback manager for this class? |
99 | | - if self._callback_manager is not None: |
100 | | - |
101 | | - # Loop through each callback in the command's list |
102 | | - for registered_callback in self[name]: |
103 | | - |
104 | | - # Is the current callback an |
105 | | - # instance for the given callback? |
106 | | - if registered_callback.callback == callback: |
107 | | - |
108 | | - # Set the callback's instance to the current callback |
109 | | - callback = registered_callback |
110 | | - |
111 | | - # Break the loop |
112 | | - break |
113 | | - |
114 | | - # Remove the callback from the command's list |
115 | | - self[name].remove(callback) |
116 | | - |
117 | | - # Are there any more callbacks registered to the command? |
118 | | - if not self[name]: |
119 | | - |
120 | | - # Remove the callback from the command's callback |
121 | | - self[name].command.remove_callback(self[name]) |
122 | | - |
123 | | - # Remove the command from the dictionary |
124 | | - del self[name] |
125 | | - |
126 | | - |
127 | | -class _CallbackList(list): |
128 | | - |
129 | | - """List class used to store.""" |
130 | | - |
131 | | - def __init__(self, command): |
132 | | - """Register the instance to the command.""" |
133 | | - # Initialize the list |
134 | | - super(_CallbackList, self).__init__() |
135 | | - |
136 | | - # Store the command |
137 | | - self.command = command |
138 | | - |
139 | | - # Add the instance to the command's callback list |
140 | | - self.command.add_callback(self) |
141 | | - |
142 | | - def __call__(self, *args): |
143 | | - """Call all callbacks for the command.""" |
144 | | - # Loop through each callback in the list |
145 | | - for callback in self: |
146 | | - |
147 | | - # Use try/except to continue the loop in case of an error |
148 | | - try: |
149 | | - |
150 | | - # Call the callback and get its return value |
151 | | - return_value = callback(*args) |
152 | | - |
153 | | - # Was an error encountered? |
154 | | - except: |
155 | | - |
156 | | - # Print the exception to the console |
157 | | - except_hooks.print_exception() |
158 | | - |
159 | | - # Was no error encountered? |
160 | | - else: |
161 | | - |
162 | | - # Does the command need blocked? |
163 | | - if not (return_value is None or return_value): |
164 | | - |
165 | | - # Block the command |
166 | | - return CommandReturn.BLOCK |
167 | | - |
168 | | - # Allow the command to continue |
169 | | - return CommandReturn.CONTINUE |
170 | | - |
171 | | - def append(self, callback): |
172 | | - """Add a callback to the list.""" |
173 | | - # Is the callback already in the list? |
174 | | - if callback in self: |
175 | | - |
176 | | - # Raise an error |
177 | | - raise ValueError('Callback already registered to command') |
178 | | - |
179 | | - # Add the callback to the list |
180 | | - super(_CallbackList, self).append(callback) |
181 | | - |
182 | | - def remove(self, callback): |
183 | | - """Remove a callback from the list.""" |
184 | | - # Is the callback in the list? |
185 | | - if callback not in self: |
186 | | - |
187 | | - # Raise an error |
188 | | - raise ValueError('Callback not registered to command') |
189 | | - |
190 | | - # Remove the callback from the list |
191 | | - super(_CallbackList, self).remove(callback) |
| 75 | + self._get_command(name).remove_callback(callback) |
0 commit comments