##// END OF EJS Templates
Merge shlex PRs (#1130, #1116)...
MinRK -
r5693:790cb143 merge
parent child Browse files
Show More
@@ -0,0 +1,69 b''
1 # -*- coding: utf-8 -*-
2 """Tests for completerlib.
3
4 """
5 from __future__ import absolute_import
6
7 #-----------------------------------------------------------------------------
8 # Imports
9 #-----------------------------------------------------------------------------
10
11 import os
12 import shutil
13 import sys
14 import tempfile
15 import unittest
16 from os.path import join
17
18 import nose.tools as nt
19 from nose import SkipTest
20
21 from IPython.core.completerlib import magic_run_completer
22 from IPython.testing import decorators as dec
23 from IPython.testing import tools as tt
24 from IPython.utils import py3compat
25
26
27 class MockEvent(object):
28 def __init__(self, line):
29 self.line = line
30
31 #-----------------------------------------------------------------------------
32 # Test functions begin
33 #-----------------------------------------------------------------------------
34 class Test_magic_run_completer(unittest.TestCase):
35 def setUp(self):
36 self.BASETESTDIR = tempfile.mkdtemp()
37 for fil in [u"aaΓΈ.py", u"a.py", u"b.py"]:
38 with open(join(self.BASETESTDIR, fil), "w") as sfile:
39 sfile.write("pass\n")
40 self.oldpath = os.getcwdu()
41 os.chdir(self.BASETESTDIR)
42
43 def tearDown(self):
44 os.chdir(self.oldpath)
45 shutil.rmtree(self.BASETESTDIR)
46
47 def test_1(self):
48 """Test magic_run_completer, should match two alterntives
49 """
50 event = MockEvent(u"%run a")
51 mockself = None
52 match = set(magic_run_completer(mockself, event))
53 self.assertEqual(match, set([u"a.py", u"aaΓΈ.py"]))
54
55 def test_2(self):
56 """Test magic_run_completer, should match one alterntive
57 """
58 event = MockEvent(u"%run aa")
59 mockself = None
60 match = set(magic_run_completer(mockself, event))
61 self.assertEqual(match, set([u"aaΓΈ.py"]))
62
63 def test_3(self):
64 """Test magic_run_completer with unterminated " """
65 event = MockEvent(u'%run "a')
66 mockself = None
67 match = set(magic_run_completer(mockself, event))
68 self.assertEqual(match, set([u"a.py", u"aaΓΈ.py"]))
69
@@ -20,7 +20,6 b' import glob'
20 import inspect
20 import inspect
21 import os
21 import os
22 import re
22 import re
23 import shlex
24 import sys
23 import sys
25
24
26 # Third-party imports
25 # Third-party imports
@@ -31,6 +30,7 b' from zipimport import zipimporter'
31 from IPython.core.completer import expand_user, compress_user
30 from IPython.core.completer import expand_user, compress_user
32 from IPython.core.error import TryNext
31 from IPython.core.error import TryNext
33 from IPython.utils import py3compat
32 from IPython.utils import py3compat
33 from IPython.utils._process_common import arg_split
34
34
35 # FIXME: this should be pulled in with the right call via the component system
35 # FIXME: this should be pulled in with the right call via the component system
36 from IPython.core.ipapi import get as get_ipython
36 from IPython.core.ipapi import get as get_ipython
@@ -56,35 +56,6 b" magic_run_re = re.compile(r'.*(\\.ipy|\\.py[w]?)$')"
56 # Local utilities
56 # Local utilities
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59 def shlex_split(x):
60 """Helper function to split lines into segments.
61 """
62 # shlex.split raises an exception if there is a syntax error in sh syntax
63 # for example if no closing " is found. This function keeps dropping the
64 # last character of the line until shlex.split does not raise
65 # an exception. It adds end of the line to the result of shlex.split
66 #
67 # Example:
68 # %run "c:/python -> ['%run','"c:/python']
69
70 # shlex.split has unicode bugs in Python 2, so encode first to str
71 if not py3compat.PY3:
72 x = py3compat.cast_bytes(x)
73
74 endofline = []
75 while x != '':
76 try:
77 comps = shlex.split(x)
78 if len(endofline) >= 1:
79 comps.append(''.join(endofline))
80 return comps
81
82 except ValueError:
83 endofline = [x[-1:]]+endofline
84 x = x[:-1]
85
86 return [''.join(endofline)]
87
88 def module_list(path):
59 def module_list(path):
89 """
60 """
90 Return the list containing the names of the modules available in the given
61 Return the list containing the names of the modules available in the given
@@ -265,7 +236,7 b' def module_completer(self,event):'
265 def magic_run_completer(self, event):
236 def magic_run_completer(self, event):
266 """Complete files that end in .py or .ipy for the %run command.
237 """Complete files that end in .py or .ipy for the %run command.
267 """
238 """
268 comps = shlex_split(event.line)
239 comps = arg_split(event.line, strict=False)
269 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
240 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
270
241
271 #print("\nev=", event) # dbg
242 #print("\nev=", event) # dbg
@@ -266,6 +266,7 b' python-profiler package from non-free.""")'
266 # Get options
266 # Get options
267 list_all = kw.get('list_all',0)
267 list_all = kw.get('list_all',0)
268 posix = kw.get('posix', os.name == 'posix')
268 posix = kw.get('posix', os.name == 'posix')
269 strict = kw.get('strict', True)
269
270
270 # Check if we have more than one argument to warrant extra processing:
271 # Check if we have more than one argument to warrant extra processing:
271 odict = {} # Dictionary with options
272 odict = {} # Dictionary with options
@@ -273,7 +274,7 b' python-profiler package from non-free.""")'
273 if len(args) >= 1:
274 if len(args) >= 1:
274 # If the list of inputs only has 0 or 1 thing in it, there's no
275 # If the list of inputs only has 0 or 1 thing in it, there's no
275 # need to look for options
276 # need to look for options
276 argv = arg_split(arg_str,posix)
277 argv = arg_split(arg_str, posix, strict)
277 # Do regular option processing
278 # Do regular option processing
278 try:
279 try:
279 opts,args = getopt(argv,opt_str,*long_opts)
280 opts,args = getopt(argv,opt_str,*long_opts)
@@ -1865,7 +1866,7 b' Currently the magic system has the following functions:\\n"""'
1865 scaling = [1, 1e3, 1e6, 1e9]
1866 scaling = [1, 1e3, 1e6, 1e9]
1866
1867
1867 opts, stmt = self.parse_options(parameter_s,'n:r:tcp:',
1868 opts, stmt = self.parse_options(parameter_s,'n:r:tcp:',
1868 posix=False)
1869 posix=False, strict=False)
1869 if stmt == "":
1870 if stmt == "":
1870 return
1871 return
1871 timefunc = timeit.default_timer
1872 timefunc = timeit.default_timer
@@ -344,3 +344,12 b' def test_psearch():'
344 with tt.AssertPrints("dict.fromkeys"):
344 with tt.AssertPrints("dict.fromkeys"):
345 _ip.run_cell("dict.fr*?")
345 _ip.run_cell("dict.fr*?")
346
346
347 def test_timeit_shlex():
348 """test shlex issues with timeit (#1109)"""
349 _ip.ex("def f(*a,**kw): pass")
350 _ip.magic('timeit -n1 "this is a bug".count(" ")')
351 _ip.magic('timeit -r1 -n1 f(" ", 1)')
352 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
353 _ip.magic('timeit -r1 -n1 ("a " + "b")')
354 _ip.magic('timeit -r1 -n1 f("a " + "b")')
355 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
@@ -146,12 +146,18 b' def getoutputerror(cmd):'
146 return py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
146 return py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
147
147
148
148
149 def arg_split(s, posix=False):
149 def arg_split(s, posix=False, strict=True):
150 """Split a command line's arguments in a shell-like manner.
150 """Split a command line's arguments in a shell-like manner.
151
151
152 This is a modified version of the standard library's shlex.split()
152 This is a modified version of the standard library's shlex.split()
153 function, but with a default of posix=False for splitting, so that quotes
153 function, but with a default of posix=False for splitting, so that quotes
154 in inputs are respected."""
154 in inputs are respected.
155
156 if strict=False, then any errors shlex.split would raise will result in the
157 unparsed remainder being the last element of the list, rather than raising.
158 This is because we sometimes use arg_split to parse things other than
159 command-line args.
160 """
155
161
156 # Unfortunately, python's shlex module is buggy with unicode input:
162 # Unfortunately, python's shlex module is buggy with unicode input:
157 # http://bugs.python.org/issue1170
163 # http://bugs.python.org/issue1170
@@ -163,7 +169,25 b' def arg_split(s, posix=False):'
163 s = s.encode('utf-8')
169 s = s.encode('utf-8')
164 lex = shlex.shlex(s, posix=posix)
170 lex = shlex.shlex(s, posix=posix)
165 lex.whitespace_split = True
171 lex.whitespace_split = True
166 tokens = list(lex)
172 # Extract tokens, ensuring that things like leaving open quotes
173 # does not cause this to raise. This is important, because we
174 # sometimes pass Python source through this (e.g. %timeit f(" ")),
175 # and it shouldn't raise an exception.
176 # It may be a bad idea to parse things that are not command-line args
177 # through this function, but we do, so let's be safe about it.
178 tokens = []
179 while True:
180 try:
181 tokens.append(lex.next())
182 except StopIteration:
183 break
184 except ValueError:
185 if strict:
186 raise
187 # couldn't parse, get remaining blob as last token
188 tokens.append(lex.token)
189 break
190
167 if is_unicode:
191 if is_unicode:
168 # Convert the tokens back to unicode.
192 # Convert the tokens back to unicode.
169 tokens = [x.decode('utf-8') for x in tokens]
193 tokens = [x.decode('utf-8') for x in tokens]
General Comments 0
You need to be logged in to leave comments. Login now