Show More
@@ -1,168 +1,170 b'' | |||||
1 | """Tests for input handlers. |
|
1 | """Tests for input handlers. | |
2 | """ |
|
2 | """ | |
3 | #----------------------------------------------------------------------------- |
|
3 | #----------------------------------------------------------------------------- | |
4 | # Module imports |
|
4 | # Module imports | |
5 | #----------------------------------------------------------------------------- |
|
5 | #----------------------------------------------------------------------------- | |
6 |
|
6 | |||
7 | # third party |
|
7 | # third party | |
8 | import nose.tools as nt |
|
8 | import nose.tools as nt | |
9 |
|
9 | |||
10 | # our own packages |
|
10 | # our own packages | |
11 | from IPython.core import autocall |
|
11 | from IPython.core import autocall | |
12 | from IPython.testing import decorators as dec |
|
12 | from IPython.testing import decorators as dec | |
13 | from IPython.testing import tools as tt |
|
13 | from IPython.testing import tools as tt | |
14 | from IPython.testing.globalipapp import get_ipython |
|
14 | from IPython.testing.globalipapp import get_ipython | |
15 | from IPython.utils import py3compat |
|
15 | from IPython.utils import py3compat | |
16 |
|
16 | |||
17 | #----------------------------------------------------------------------------- |
|
17 | #----------------------------------------------------------------------------- | |
18 | # Globals |
|
18 | # Globals | |
19 | #----------------------------------------------------------------------------- |
|
19 | #----------------------------------------------------------------------------- | |
20 |
|
20 | |||
21 | # Get the public instance of IPython |
|
21 | # Get the public instance of IPython | |
22 | ip = get_ipython() |
|
22 | ip = get_ipython() | |
23 |
|
23 | |||
24 | failures = [] |
|
24 | failures = [] | |
25 | num_tests = 0 |
|
25 | num_tests = 0 | |
26 |
|
26 | |||
27 | #----------------------------------------------------------------------------- |
|
27 | #----------------------------------------------------------------------------- | |
28 | # Test functions |
|
28 | # Test functions | |
29 | #----------------------------------------------------------------------------- |
|
29 | #----------------------------------------------------------------------------- | |
30 |
|
30 | |||
31 | class CallableIndexable(object): |
|
31 | class CallableIndexable(object): | |
32 | def __getitem__(self, idx): return True |
|
32 | def __getitem__(self, idx): return True | |
33 | def __call__(self, *args, **kws): return True |
|
33 | def __call__(self, *args, **kws): return True | |
34 |
|
34 | |||
35 |
|
35 | |||
36 | class Autocallable(autocall.IPyAutocall): |
|
36 | class Autocallable(autocall.IPyAutocall): | |
37 | def __call__(self): |
|
37 | def __call__(self): | |
38 | return "called" |
|
38 | return "called" | |
39 |
|
39 | |||
40 |
|
40 | |||
41 | def run(tests): |
|
41 | def run(tests): | |
42 | """Loop through a list of (pre, post) inputs, where pre is the string |
|
42 | """Loop through a list of (pre, post) inputs, where pre is the string | |
43 | handed to ipython, and post is how that string looks after it's been |
|
43 | handed to ipython, and post is how that string looks after it's been | |
44 | transformed (i.e. ipython's notion of _i)""" |
|
44 | transformed (i.e. ipython's notion of _i)""" | |
45 | tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests) |
|
45 | tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests) | |
46 |
|
46 | |||
47 |
|
47 | |||
48 | def test_handlers(): |
|
48 | def test_handlers(): | |
49 | # alias expansion |
|
49 | # alias expansion | |
50 |
|
50 | |||
51 | # We're using 'true' as our syscall of choice because it doesn't |
|
51 | # We're using 'true' as our syscall of choice because it doesn't | |
52 | # write anything to stdout. |
|
52 | # write anything to stdout. | |
53 |
|
53 | |||
54 | # Turn off actual execution of aliases, because it's noisy |
|
54 | # Turn off actual execution of aliases, because it's noisy | |
55 | old_system_cmd = ip.system |
|
55 | old_system_cmd = ip.system | |
56 | ip.system = lambda cmd: None |
|
56 | ip.system = lambda cmd: None | |
57 |
|
57 | |||
58 |
|
58 | |||
59 | ip.alias_manager.alias_table['an_alias'] = (0, 'true') |
|
59 | ip.alias_manager.alias_table['an_alias'] = (0, 'true') | |
60 | # These are useful for checking a particular recursive alias issue |
|
60 | # These are useful for checking a particular recursive alias issue | |
61 | ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top') |
|
61 | ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top') | |
62 | ip.alias_manager.alias_table['d'] = (0, 'true') |
|
62 | ip.alias_manager.alias_table['d'] = (0, 'true') | |
63 | run([(i,py3compat.u_format(o)) for i,o in \ |
|
63 | run([(i,py3compat.u_format(o)) for i,o in \ | |
64 | [("an_alias", "get_ipython().system({u}'true ')"), # alias |
|
64 | [("an_alias", "get_ipython().system({u}'true ')"), # alias | |
65 | # Below: recursive aliases should expand whitespace-surrounded |
|
65 | # Below: recursive aliases should expand whitespace-surrounded | |
66 | # chars, *not* initial chars which happen to be aliases: |
|
66 | # chars, *not* initial chars which happen to be aliases: | |
67 | ("top", "get_ipython().system({u}'d:/cygwin/top ')"), |
|
67 | ("top", "get_ipython().system({u}'d:/cygwin/top ')"), | |
68 | ]]) |
|
68 | ]]) | |
69 | ip.system = old_system_cmd |
|
69 | ip.system = old_system_cmd | |
70 |
|
70 | |||
71 | call_idx = CallableIndexable() |
|
71 | call_idx = CallableIndexable() | |
72 | ip.user_ns['call_idx'] = call_idx |
|
72 | ip.user_ns['call_idx'] = call_idx | |
73 |
|
73 | |||
74 | # For many of the below, we're also checking that leading whitespace |
|
74 | # For many of the below, we're also checking that leading whitespace | |
75 | # turns off the esc char, which it should unless there is a continuation |
|
75 | # turns off the esc char, which it should unless there is a continuation | |
76 | # line. |
|
76 | # line. | |
77 | run([(i,py3compat.u_format(o)) for i,o in \ |
|
77 | run([(i,py3compat.u_format(o)) for i,o in \ | |
78 | [('"no change"', '"no change"'), # normal |
|
78 | [('"no change"', '"no change"'), # normal | |
79 | (u"!true", "get_ipython().system({u}'true')"), # shell_escapes |
|
79 | (u"!true", "get_ipython().system({u}'true')"), # shell_escapes | |
80 | (u"!! true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic |
|
80 | (u"!! true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic | |
81 | (u"!!true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic |
|
81 | (u"!!true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic | |
82 | (u"%lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic |
|
82 | (u"%lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic | |
83 | (u"lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic |
|
83 | (u"lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic | |
84 | #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache |
|
84 | #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache | |
85 |
|
85 | |||
86 | # post-esc-char whitespace goes inside |
|
86 | # post-esc-char whitespace goes inside | |
87 | (u"! true", "get_ipython().system({u}' true')"), |
|
87 | (u"! true", "get_ipython().system({u}' true')"), | |
88 |
|
88 | |||
89 | # handle_help |
|
89 | # handle_help | |
90 |
|
90 | |||
91 | # These are weak tests -- just looking at what the help handlers |
|
91 | # These are weak tests -- just looking at what the help handlers | |
92 | # logs, which is not how it really does its work. But it still |
|
92 | # logs, which is not how it really does its work. But it still | |
93 | # lets us check the key paths through the handler. |
|
93 | # lets us check the key paths through the handler. | |
94 |
|
94 | |||
95 | ("x=1 # what?", "x=1 # what?"), # no help if valid python |
|
95 | ("x=1 # what?", "x=1 # what?"), # no help if valid python | |
96 | ]]) |
|
96 | ]]) | |
97 |
|
97 | |||
98 | # multi_line_specials |
|
98 | # multi_line_specials | |
99 | ip.prefilter_manager.multi_line_specials = False |
|
99 | ip.prefilter_manager.multi_line_specials = False | |
100 | # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion |
|
100 | # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion | |
101 | run([ |
|
101 | run([ | |
102 | (u'if 1:\n !true', u'if 1:\n !true'), |
|
102 | (u'if 1:\n !true', u'if 1:\n !true'), | |
103 | (u'if 1:\n lsmagic', u'if 1:\n lsmagic'), |
|
103 | (u'if 1:\n lsmagic', u'if 1:\n lsmagic'), | |
104 | (u'if 1:\n an_alias', u'if 1:\n an_alias'), |
|
104 | (u'if 1:\n an_alias', u'if 1:\n an_alias'), | |
105 | ]) |
|
105 | ]) | |
106 |
|
106 | |||
107 | ip.prefilter_manager.multi_line_specials = True |
|
107 | ip.prefilter_manager.multi_line_specials = True | |
108 | # initial indents must be preserved. |
|
108 | # initial indents must be preserved. | |
109 | run([(i,py3compat.u_format(o)) for i,o in \ |
|
109 | run([(i,py3compat.u_format(o)) for i,o in \ | |
110 | [(u'if 1:\n !true', "if 1:\n get_ipython().system({u}'true')"), |
|
110 | [(u'if 1:\n !true', "if 1:\n get_ipython().system({u}'true')"), | |
111 | (u'if 2:\n lsmagic', "if 2:\n get_ipython().magic({u}'lsmagic ')"), |
|
111 | (u'if 2:\n lsmagic', "if 2:\n get_ipython().magic({u}'lsmagic ')"), | |
112 | (u'if 1:\n an_alias', "if 1:\n get_ipython().system({u}'true ')"), |
|
112 | (u'if 1:\n an_alias', "if 1:\n get_ipython().system({u}'true ')"), | |
113 | # Weird one |
|
113 | # Weird one | |
114 | (u'if 1:\n !!true', "if 1:\n get_ipython().magic({u}'sx true')"), |
|
114 | (u'if 1:\n !!true', "if 1:\n get_ipython().magic({u}'sx true')"), | |
115 |
|
115 | |||
116 | # Even with m_l_s on, autocall is off even with special chars |
|
116 | # Even with m_l_s on, autocall is off even with special chars | |
117 | ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'), |
|
117 | ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'), | |
118 | ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'), |
|
118 | ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'), | |
119 | ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'), |
|
119 | ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'), | |
120 | ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'), |
|
120 | ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'), | |
121 | # What about !! |
|
121 | # What about !! | |
122 | ]]) |
|
122 | ]]) | |
123 |
|
123 | |||
124 | # Objects which are instances of IPyAutocall are *always* autocalled |
|
124 | # Objects which are instances of IPyAutocall are *always* autocalled | |
125 | autocallable = Autocallable() |
|
125 | autocallable = Autocallable() | |
126 | ip.user_ns['autocallable'] = autocallable |
|
126 | ip.user_ns['autocallable'] = autocallable | |
127 |
|
127 | |||
128 | # auto |
|
128 | # auto | |
129 | ip.magic('autocall 0') |
|
129 | ip.magic('autocall 0') | |
130 | # Only explicit escapes or instances of IPyAutocallable should get |
|
130 | # Only explicit escapes or instances of IPyAutocallable should get | |
131 | # expanded |
|
131 | # expanded | |
132 | run([ |
|
132 | run([ | |
133 | ('len "abc"', 'len "abc"'), |
|
133 | ('len "abc"', 'len "abc"'), | |
134 | ('autocallable', 'autocallable()'), |
|
134 | ('autocallable', 'autocallable()'), | |
|
135 | # Don't add extra brackets (gh-1117) | |||
|
136 | ('autocallable()', 'autocallable ()'), | |||
135 | (",list 1 2 3", 'list("1", "2", "3")'), |
|
137 | (",list 1 2 3", 'list("1", "2", "3")'), | |
136 | (";list 1 2 3", 'list("1 2 3")'), |
|
138 | (";list 1 2 3", 'list("1 2 3")'), | |
137 | ("/len range(1,4)", 'len(range(1,4))'), |
|
139 | ("/len range(1,4)", 'len(range(1,4))'), | |
138 | ]) |
|
140 | ]) | |
139 | ip.magic('autocall 1') |
|
141 | ip.magic('autocall 1') | |
140 | run([ |
|
142 | run([ | |
141 | (",list 1 2 3", 'list("1", "2", "3")'), |
|
143 | (",list 1 2 3", 'list("1", "2", "3")'), | |
142 | (";list 1 2 3", 'list("1 2 3")'), |
|
144 | (";list 1 2 3", 'list("1 2 3")'), | |
143 | ("/len range(1,4)", 'len(range(1,4))'), |
|
145 | ("/len range(1,4)", 'len(range(1,4))'), | |
144 | ('len "abc"', 'len("abc")'), |
|
146 | ('len "abc"', 'len("abc")'), | |
145 | ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens |
|
147 | ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens | |
146 | # Autocall is turned off if first arg is [] and the object |
|
148 | # Autocall is turned off if first arg is [] and the object | |
147 | # is both callable and indexable. Like so: |
|
149 | # is both callable and indexable. Like so: | |
148 | ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__... |
|
150 | ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__... | |
149 | ('call_idx [1]', 'call_idx [1]'), # call_idx *does*.. |
|
151 | ('call_idx [1]', 'call_idx [1]'), # call_idx *does*.. | |
150 | ('call_idx 1', 'call_idx(1)'), |
|
152 | ('call_idx 1', 'call_idx(1)'), | |
151 | ('len', 'len '), # only at 2 does it auto-call on single args |
|
153 | ('len', 'len '), # only at 2 does it auto-call on single args | |
152 | ]) |
|
154 | ]) | |
153 | ip.magic('autocall 2') |
|
155 | ip.magic('autocall 2') | |
154 | run([ |
|
156 | run([ | |
155 | (",list 1 2 3", 'list("1", "2", "3")'), |
|
157 | (",list 1 2 3", 'list("1", "2", "3")'), | |
156 | (";list 1 2 3", 'list("1 2 3")'), |
|
158 | (";list 1 2 3", 'list("1 2 3")'), | |
157 | ("/len range(1,4)", 'len(range(1,4))'), |
|
159 | ("/len range(1,4)", 'len(range(1,4))'), | |
158 | ('len "abc"', 'len("abc")'), |
|
160 | ('len "abc"', 'len("abc")'), | |
159 | ('len "abc";', 'len("abc");'), |
|
161 | ('len "abc";', 'len("abc");'), | |
160 | ('len [1,2]', 'len([1,2])'), |
|
162 | ('len [1,2]', 'len([1,2])'), | |
161 | ('call_idx [1]', 'call_idx [1]'), |
|
163 | ('call_idx [1]', 'call_idx [1]'), | |
162 | ('call_idx 1', 'call_idx(1)'), |
|
164 | ('call_idx 1', 'call_idx(1)'), | |
163 | # This is what's different: |
|
165 | # This is what's different: | |
164 | ('len', 'len()'), # only at 2 does it auto-call on single args |
|
166 | ('len', 'len()'), # only at 2 does it auto-call on single args | |
165 | ]) |
|
167 | ]) | |
166 | ip.magic('autocall 1') |
|
168 | ip.magic('autocall 1') | |
167 |
|
169 | |||
168 | nt.assert_equals(failures, []) |
|
170 | nt.assert_equals(failures, []) |
General Comments 0
You need to be logged in to leave comments.
Login now