##// END OF EJS Templates
Merge pull request #1850 from bfroehle/_1736_try_next...
Thomas Kluyver -
r7341:d7c7a8f5 merge
parent child Browse files
Show More
@@ -0,0 +1,75 b''
1 # -*- coding: utf-8 -*-
2 """Tests for CommandChainDispatcher."""
3
4 from __future__ import absolute_import
5
6 #-----------------------------------------------------------------------------
7 # Imports
8 #-----------------------------------------------------------------------------
9
10 import nose.tools as nt
11 from IPython.core.error import TryNext
12 from IPython.core.hooks import CommandChainDispatcher
13
14 #-----------------------------------------------------------------------------
15 # Local utilities
16 #-----------------------------------------------------------------------------
17
18 # Define two classes, one which succeeds and one which raises TryNext. Each
19 # sets the attribute `called` to True when it is called.
20 class Okay(object):
21 def __init__(self, message):
22 self.message = message
23 self.called = False
24 def __call__(self):
25 self.called = True
26 return self.message
27
28 class Fail(object):
29 def __init__(self, message):
30 self.message = message
31 self.called = False
32 def __call__(self):
33 self.called = True
34 raise TryNext(self.message)
35
36 #-----------------------------------------------------------------------------
37 # Test functions
38 #-----------------------------------------------------------------------------
39
40 def test_command_chain_dispatcher_ff():
41 """Test two failing hooks"""
42 fail1 = Fail(u'fail1')
43 fail2 = Fail(u'fail2')
44 dp = CommandChainDispatcher([(0, fail1),
45 (10, fail2)])
46
47 try:
48 dp()
49 except TryNext as e:
50 nt.assert_equal(str(e), u'fail2')
51 else:
52 assert False, "Expected exception was not raised."
53
54 nt.assert_true(fail1.called)
55 nt.assert_true(fail2.called)
56
57 def test_command_chain_dispatcher_fofo():
58 """Test a mixture of failing and succeeding hooks."""
59 fail1 = Fail(u'fail1')
60 fail2 = Fail(u'fail2')
61 okay1 = Okay(u'okay1')
62 okay2 = Okay(u'okay2')
63
64 dp = CommandChainDispatcher([(0, fail1),
65 # (5, okay1), # add this later
66 (10, fail2),
67 (15, okay2)])
68 dp.add(okay1, 5)
69
70 nt.assert_equal(dp(), u'okay1')
71
72 nt.assert_true(fail1.called)
73 nt.assert_true(okay1.called)
74 nt.assert_false(fail2.called)
75 nt.assert_false(okay2.called)
@@ -35,22 +35,9 b' class TryNext(IPythonCoreError):'
35 """Try next hook exception.
35 """Try next hook exception.
36
36
37 Raise this in your hook function to indicate that the next hook handler
37 Raise this in your hook function to indicate that the next hook handler
38 should be used to handle the operation. If you pass arguments to the
38 should be used to handle the operation.
39 constructor those arguments will be used by the next hook instead of the
40 original ones.
41
42 A _msg argument will not be passed on, so it can be used as a displayable
43 error message.
44 """
39 """
45
40
46 def __init__(self, _msg="", *args, **kwargs):
47 self.args = args
48 self.kwargs = kwargs
49 self.msg = _msg
50
51 def __str__(self):
52 return str(self.msg)
53
54 class UsageError(IPythonCoreError):
41 class UsageError(IPythonCoreError):
55 """Error in magic function arguments, etc.
42 """Error in magic function arguments, etc.
56
43
@@ -131,17 +131,15 b' class CommandChainDispatcher:'
131 This will call all funcs in chain with the same args as were given to
131 This will call all funcs in chain with the same args as were given to
132 this function, and return the result of first func that didn't raise
132 this function, and return the result of first func that didn't raise
133 TryNext"""
133 TryNext"""
134
134 last_exc = TryNext()
135 for prio,cmd in self.chain:
135 for prio,cmd in self.chain:
136 #print "prio",prio,"cmd",cmd #dbg
136 #print "prio",prio,"cmd",cmd #dbg
137 try:
137 try:
138 return cmd(*args, **kw)
138 return cmd(*args, **kw)
139 except TryNext, exc:
139 except TryNext as exc:
140 if exc.args or exc.kwargs:
140 last_exc = exc
141 args = exc.args
142 kw = exc.kwargs
143 # if no function will accept it, raise TryNext up to the caller
141 # if no function will accept it, raise TryNext up to the caller
144 raise TryNext(*args, **kw)
142 raise last_exc
145
143
146 def __str__(self):
144 def __str__(self):
147 return str(self.chain)
145 return str(self.chain)
@@ -15,9 +15,8 b' def win32_clipboard_get():'
15 try:
15 try:
16 import win32clipboard
16 import win32clipboard
17 except ImportError:
17 except ImportError:
18 message = ("Getting text from the clipboard requires the pywin32 "
18 raise TryNext("Getting text from the clipboard requires the pywin32 "
19 "extensions: http://sourceforge.net/projects/pywin32/")
19 "extensions: http://sourceforge.net/projects/pywin32/")
20 raise TryNext(_msg=message)
21 win32clipboard.OpenClipboard()
20 win32clipboard.OpenClipboard()
22 text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
21 text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
23 # FIXME: convert \r\n to \n?
22 # FIXME: convert \r\n to \n?
@@ -44,9 +43,8 b' def tkinter_clipboard_get():'
44 try:
43 try:
45 import Tkinter
44 import Tkinter
46 except ImportError:
45 except ImportError:
47 message = ("Getting text from the clipboard on this platform "
46 raise TryNext("Getting text from the clipboard on this platform "
48 "requires Tkinter.")
47 "requires Tkinter.")
49 raise TryNext(_msg=message)
50 root = Tkinter.Tk()
48 root = Tkinter.Tk()
51 root.withdraw()
49 root.withdraw()
52 text = root.clipboard_get()
50 text = root.clipboard_get()
@@ -25,3 +25,11 b' Other new features'
25 :meth:`~IPython.core.interactiveshell.InteractiveShell.run_cell` to
25 :meth:`~IPython.core.interactiveshell.InteractiveShell.run_cell` to
26 :meth:`~IPython.core.interactiveshell.InteractiveShell.run_ast_nodes`
26 :meth:`~IPython.core.interactiveshell.InteractiveShell.run_ast_nodes`
27 is now configurable.
27 is now configurable.
28
29 Backwards incompatible changes
30 ------------------------------
31
32 * The exception :exc:`IPython.core.error.TryNext` previously accepted
33 arguments and keyword arguments to be passed to the next implementation
34 of the hook. This feature was removed as it made error message propagation
35 difficult and violated the principle of loose coupling.
General Comments 0
You need to be logged in to leave comments. Login now