Show More
@@ -476,8 +476,8 b' class PythonOpsChecker(PrefilterChecker):' | |||
|
476 | 476 | any python operator, we should simply execute the line (regardless of |
|
477 | 477 | whether or not there's a possible autocall expansion). This avoids |
|
478 | 478 | spurious (and very confusing) geattr() accesses.""" |
|
479 |
if line_info.the_rest and line_info.the_rest[0] in |
|
|
480 |
return self.prefilter_manager.get_handler_by_name( |
|
|
479 | if line_info.the_rest and line_info.the_rest[0] in "!=()<>,+*/%^&|": | |
|
480 | return self.prefilter_manager.get_handler_by_name("normal") | |
|
481 | 481 | else: |
|
482 | 482 | return None |
|
483 | 483 | |
@@ -512,6 +512,8 b' class AutocallChecker(PrefilterChecker):' | |||
|
512 | 512 | callable(oinfo.obj) |
|
513 | 513 | and (not self.exclude_regexp.match(line_info.the_rest)) |
|
514 | 514 | and self.function_name_regexp.match(line_info.ifun) |
|
515 | and line_info.raw_the_rest.startswith(" ") | |
|
516 | or not line_info.raw_the_rest.strip() | |
|
515 | 517 | ): |
|
516 | 518 | return self.prefilter_manager.get_handler_by_name("auto") |
|
517 | 519 | else: |
@@ -76,7 +76,7 b' def split_user_input(line, pattern=None):' | |||
|
76 | 76 | |
|
77 | 77 | # print('line:<%s>' % line) # dbg |
|
78 | 78 | # print('pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest)) # dbg |
|
79 |
return pre, esc or |
|
|
79 | return pre, esc or "", ifun.strip(), the_rest | |
|
80 | 80 | |
|
81 | 81 | |
|
82 | 82 | class LineInfo(object): |
@@ -107,11 +107,15 b' class LineInfo(object):' | |||
|
107 | 107 | |
|
108 | 108 | the_rest |
|
109 | 109 | Everything else on the line. |
|
110 | ||
|
111 | raw_the_rest | |
|
112 | the_rest without whitespace stripped. | |
|
110 | 113 | """ |
|
111 | 114 | def __init__(self, line, continue_prompt=False): |
|
112 | 115 | self.line = line |
|
113 | 116 | self.continue_prompt = continue_prompt |
|
114 | self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line) | |
|
117 | self.pre, self.esc, self.ifun, self.raw_the_rest = split_user_input(line) | |
|
118 | self.the_rest = self.raw_the_rest.lstrip() | |
|
115 | 119 | |
|
116 | 120 | self.pre_char = self.pre.strip() |
|
117 | 121 | if self.pre_char: |
@@ -136,3 +140,6 b' class LineInfo(object):' | |||
|
136 | 140 | |
|
137 | 141 | def __str__(self): |
|
138 | 142 | return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest) |
|
143 | ||
|
144 | def __repr__(self): | |
|
145 | return "<" + str(self) + ">" |
@@ -7,17 +7,13 b'' | |||
|
7 | 7 | # our own packages |
|
8 | 8 | from IPython.core import autocall |
|
9 | 9 | from IPython.testing import tools as tt |
|
10 | import pytest | |
|
11 | from collections.abc import Callable | |
|
10 | 12 | |
|
11 | 13 | #----------------------------------------------------------------------------- |
|
12 | 14 | # Globals |
|
13 | 15 | #----------------------------------------------------------------------------- |
|
14 | 16 | |
|
15 | # Get the public instance of IPython | |
|
16 | ||
|
17 | failures = [] | |
|
18 | num_tests = 0 | |
|
19 | ||
|
20 | #----------------------------------------------------------------------------- | |
|
21 | 17 | # Test functions |
|
22 | 18 | #----------------------------------------------------------------------------- |
|
23 | 19 | |
@@ -31,67 +27,49 b' class Autocallable(autocall.IPyAutocall):' | |||
|
31 | 27 | return "called" |
|
32 | 28 | |
|
33 | 29 | |
|
34 | def run(tests): | |
|
35 | """Loop through a list of (pre, post) inputs, where pre is the string | |
|
36 | handed to ipython, and post is how that string looks after it's been | |
|
37 | transformed (i.e. ipython's notion of _i)""" | |
|
38 | tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests) | |
|
39 | ||
|
30 | @pytest.mark.parametrize( | |
|
31 | "autocall, input, output", | |
|
32 | [ | |
|
33 | # For many of the below, we're also checking that leading whitespace | |
|
34 | # turns off the esc char, which it should unless there is a continuation | |
|
35 | # line. | |
|
36 | ("1", '"no change"', '"no change"'), # normal | |
|
37 | ("1", "lsmagic", "get_ipython().run_line_magic('lsmagic', '')"), # magic | |
|
38 | # Only explicit escapes or instances of IPyAutocallable should get | |
|
39 | # expanded | |
|
40 | ("0", 'len "abc"', 'len "abc"'), | |
|
41 | ("0", "autocallable", "autocallable()"), | |
|
42 | # Don't add extra brackets (gh-1117) | |
|
43 | ("0", "autocallable()", "autocallable()"), | |
|
44 | ("1", 'len "abc"', 'len("abc")'), | |
|
45 | ("1", 'len "abc";', 'len("abc");'), # ; is special -- moves out of parens | |
|
46 | # Autocall is turned off if first arg is [] and the object | |
|
47 | # is both callable and indexable. Like so: | |
|
48 | ("1", "len [1,2]", "len([1,2])"), # len doesn't support __getitem__... | |
|
49 | ("1", "call_idx [1]", "call_idx [1]"), # call_idx *does*.. | |
|
50 | ("1", "call_idx 1", "call_idx(1)"), | |
|
51 | ("1", "len", "len"), # only at 2 does it auto-call on single args | |
|
52 | ("2", 'len "abc"', 'len("abc")'), | |
|
53 | ("2", 'len "abc";', 'len("abc");'), | |
|
54 | ("2", "len [1,2]", "len([1,2])"), | |
|
55 | ("2", "call_idx [1]", "call_idx [1]"), | |
|
56 | ("2", "call_idx 1", "call_idx(1)"), | |
|
57 | # T his is what's different: | |
|
58 | ("2", "len", "len()"), # only at 2 does it auto-call on single args | |
|
59 | ("0", "Callable[[int], None]", "Callable[[int], None]"), | |
|
60 | ("1", "Callable[[int], None]", "Callable[[int], None]"), | |
|
61 | ("1", "Callable[[int], None]", "Callable[[int], None]"), | |
|
62 | ], | |
|
63 | ) | |
|
64 | def test_handlers_I(autocall, input, output): | |
|
65 | autocallable = Autocallable() | |
|
66 | ip.user_ns["autocallable"] = autocallable | |
|
40 | 67 | |
|
41 | def test_handlers(): | |
|
42 | 68 | call_idx = CallableIndexable() |
|
43 |
ip.user_ns[ |
|
|
69 | ip.user_ns["call_idx"] = call_idx | |
|
44 | 70 | |
|
45 | # For many of the below, we're also checking that leading whitespace | |
|
46 | # turns off the esc char, which it should unless there is a continuation | |
|
47 | # line. | |
|
48 | run( | |
|
49 | [('"no change"', '"no change"'), # normal | |
|
50 | (u"lsmagic", "get_ipython().run_line_magic('lsmagic', '')"), # magic | |
|
51 | #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache | |
|
52 | ]) | |
|
71 | ip.user_ns["Callable"] = Callable | |
|
53 | 72 | |
|
54 | # Objects which are instances of IPyAutocall are *always* autocalled | |
|
55 | autocallable = Autocallable() | |
|
56 | ip.user_ns['autocallable'] = autocallable | |
|
57 | ||
|
58 | # auto | |
|
59 | ip.run_line_magic("autocall", "0") | |
|
60 | # Only explicit escapes or instances of IPyAutocallable should get | |
|
61 | # expanded | |
|
62 | run( | |
|
63 | [ | |
|
64 | ('len "abc"', 'len "abc"'), | |
|
65 | ("autocallable", "autocallable()"), | |
|
66 | # Don't add extra brackets (gh-1117) | |
|
67 | ("autocallable()", "autocallable()"), | |
|
68 | ] | |
|
69 | ) | |
|
73 | ip.run_line_magic("autocall", autocall) | |
|
74 | assert ip.prefilter_manager.prefilter_lines(input) == output | |
|
70 | 75 | ip.run_line_magic("autocall", "1") |
|
71 | run( | |
|
72 | [ | |
|
73 | ('len "abc"', 'len("abc")'), | |
|
74 | ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens | |
|
75 | # Autocall is turned off if first arg is [] and the object | |
|
76 | # is both callable and indexable. Like so: | |
|
77 | ("len [1,2]", "len([1,2])"), # len doesn't support __getitem__... | |
|
78 | ("call_idx [1]", "call_idx [1]"), # call_idx *does*.. | |
|
79 | ("call_idx 1", "call_idx(1)"), | |
|
80 | ("len", "len"), # only at 2 does it auto-call on single args | |
|
81 | ] | |
|
82 | ) | |
|
83 | ip.run_line_magic("autocall", "2") | |
|
84 | run( | |
|
85 | [ | |
|
86 | ('len "abc"', 'len("abc")'), | |
|
87 | ('len "abc";', 'len("abc");'), | |
|
88 | ("len [1,2]", "len([1,2])"), | |
|
89 | ("call_idx [1]", "call_idx [1]"), | |
|
90 | ("call_idx 1", "call_idx(1)"), | |
|
91 | # This is what's different: | |
|
92 | ("len", "len()"), # only at 2 does it auto-call on single args | |
|
93 | ] | |
|
94 | ) | |
|
95 | ip.run_line_magic("autocall", "1") | |
|
96 | ||
|
97 | assert failures == [] |
@@ -48,7 +48,7 b' def test_prefilter_shadowed():' | |||
|
48 | 48 | |
|
49 | 49 | def test_autocall_binops(): |
|
50 | 50 | """See https://github.com/ipython/ipython/issues/81""" |
|
51 |
ip.magic( |
|
|
51 | ip.run_line_magic("autocall", "2") | |
|
52 | 52 | f = lambda x: x |
|
53 | 53 | ip.user_ns['f'] = f |
|
54 | 54 | try: |
@@ -71,8 +71,8 b' def test_autocall_binops():' | |||
|
71 | 71 | finally: |
|
72 | 72 | pm.unregister_checker(ac) |
|
73 | 73 | finally: |
|
74 |
ip.magic( |
|
|
75 |
del ip.user_ns[ |
|
|
74 | ip.run_line_magic("autocall", "0") | |
|
75 | del ip.user_ns["f"] | |
|
76 | 76 | |
|
77 | 77 | |
|
78 | 78 | def test_issue_114(): |
@@ -105,23 +105,35 b' def test_prefilter_attribute_errors():' | |||
|
105 | 105 | return x |
|
106 | 106 | |
|
107 | 107 | # Create a callable broken object |
|
108 |
ip.user_ns[ |
|
|
109 |
ip.magic( |
|
|
108 | ip.user_ns["x"] = X() | |
|
109 | ip.run_line_magic("autocall", "2") | |
|
110 | 110 | try: |
|
111 | 111 | # Even if x throws an attribute error when looking at its rewrite |
|
112 | 112 | # attribute, we should not crash. So the test here is simply making |
|
113 | 113 | # the prefilter call and not having an exception. |
|
114 | 114 | ip.prefilter('x 1') |
|
115 | 115 | finally: |
|
116 |
del ip.user_ns[ |
|
|
117 |
ip.magic( |
|
|
116 | del ip.user_ns["x"] | |
|
117 | ip.run_line_magic("autocall", "0") | |
|
118 | ||
|
119 | ||
|
120 | def test_autocall_type_ann(): | |
|
121 | ip.run_cell("import collections.abc") | |
|
122 | ip.run_line_magic("autocall", "1") | |
|
123 | try: | |
|
124 | assert ( | |
|
125 | ip.prefilter("collections.abc.Callable[[int], None]") | |
|
126 | == "collections.abc.Callable[[int], None]" | |
|
127 | ) | |
|
128 | finally: | |
|
129 | ip.run_line_magic("autocall", "0") | |
|
118 | 130 | |
|
119 | 131 | |
|
120 | 132 | def test_autocall_should_support_unicode(): |
|
121 |
ip.magic( |
|
|
122 |
ip.user_ns[ |
|
|
133 | ip.run_line_magic("autocall", "2") | |
|
134 | ip.user_ns["π"] = lambda x: x | |
|
123 | 135 | try: |
|
124 | 136 | assert ip.prefilter("π 3") == "π(3)" |
|
125 | 137 | finally: |
|
126 |
ip.magic( |
|
|
127 |
del ip.user_ns[ |
|
|
138 | ip.run_line_magic("autocall", "0") | |
|
139 | del ip.user_ns["π"] |
@@ -1,7 +1,8 b'' | |||
|
1 | 1 | # coding: utf-8 |
|
2 | 2 | |
|
3 | 3 | from IPython.core.splitinput import split_user_input, LineInfo |
|
4 | from IPython.testing import tools as tt | |
|
4 | ||
|
5 | import pytest | |
|
5 | 6 | |
|
6 | 7 | tests = [ |
|
7 | 8 | ("x=1", ("", "", "x", "=1")), |
@@ -19,18 +20,19 b' tests = [' | |||
|
19 | 20 | (";ls", ("", ";", "ls", "")), |
|
20 | 21 | (" ;ls", (" ", ";", "ls", "")), |
|
21 | 22 | ("f.g(x)", ("", "", "f.g", "(x)")), |
|
22 | ("f.g (x)", ("", "", "f.g", "(x)")), | |
|
23 | ("f.g (x)", ("", "", "f.g", " (x)")), | |
|
23 | 24 | ("?%hist1", ("", "?", "%hist1", "")), |
|
24 | 25 | ("?%%hist2", ("", "?", "%%hist2", "")), |
|
25 | 26 | ("??%hist3", ("", "??", "%hist3", "")), |
|
26 | 27 | ("??%%hist4", ("", "??", "%%hist4", "")), |
|
27 | 28 | ("?x*", ("", "?", "x*", "")), |
|
29 | ("Pérez Fernando", ("", "", "Pérez", " Fernando")), | |
|
28 | 30 | ] |
|
29 | tests.append(("Pérez Fernando", ("", "", "Pérez", "Fernando"))) | |
|
30 | 31 | |
|
31 | 32 | |
|
32 | def test_split_user_input(): | |
|
33 | return tt.check_pairs(split_user_input, tests) | |
|
33 | @pytest.mark.parametrize("input, output", tests) | |
|
34 | def test_split_user_input(input, output): | |
|
35 | assert split_user_input(input) == output | |
|
34 | 36 | |
|
35 | 37 | |
|
36 | 38 | def test_LineInfo(): |
General Comments 0
You need to be logged in to leave comments.
Login now