##// END OF EJS Templates
Fix %history to stop printing last line....
Fernando Perez -
Show More
@@ -1,274 +1,276 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """ History related magics and functionality """
2 """ History related magics and functionality """
3
3
4 # Stdlib imports
4 # Stdlib imports
5 import fnmatch
5 import fnmatch
6 import os
6 import os
7
7
8 from IPython.utils.genutils import Term, ask_yes_no, warn
8 from IPython.utils.genutils import Term, ask_yes_no, warn
9 from IPython.core import ipapi
9 from IPython.core import ipapi
10
10
11 def magic_history(self, parameter_s = ''):
11 def magic_history(self, parameter_s = ''):
12 """Print input history (_i<n> variables), with most recent last.
12 """Print input history (_i<n> variables), with most recent last.
13
13
14 %history -> print at most 40 inputs (some may be multi-line)\\
14 %history -> print at most 40 inputs (some may be multi-line)\\
15 %history n -> print at most n inputs\\
15 %history n -> print at most n inputs\\
16 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
16 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
17
17
18 By default, input history is printed without line numbers so it can be
18 By default, input history is printed without line numbers so it can be
19 directly pasted into an editor.
19 directly pasted into an editor.
20
20
21 With -n, each input's number <n> is shown, and is accessible as the
21 With -n, each input's number <n> is shown, and is accessible as the
22 automatically generated variable _i<n> as well as In[<n>]. Multi-line
22 automatically generated variable _i<n> as well as In[<n>]. Multi-line
23 statements are printed starting at a new line for easy copy/paste.
23 statements are printed starting at a new line for easy copy/paste.
24
24
25 Options:
25 Options:
26
26
27 -n: print line numbers for each input.
27 -n: print line numbers for each input.
28 This feature is only available if numbered prompts are in use.
28 This feature is only available if numbered prompts are in use.
29
29
30 -o: also print outputs for each input.
30 -o: also print outputs for each input.
31
31
32 -p: print classic '>>>' python prompts before each input. This is useful
32 -p: print classic '>>>' python prompts before each input. This is useful
33 for making documentation, and in conjunction with -o, for producing
33 for making documentation, and in conjunction with -o, for producing
34 doctest-ready output.
34 doctest-ready output.
35
35
36 -t: (default) print the 'translated' history, as IPython understands it.
36 -t: (default) print the 'translated' history, as IPython understands it.
37 IPython filters your input and converts it all into valid Python source
37 IPython filters your input and converts it all into valid Python source
38 before executing it (things like magics or aliases are turned into
38 before executing it (things like magics or aliases are turned into
39 function calls, for example). With this option, you'll see the native
39 function calls, for example). With this option, you'll see the native
40 history instead of the user-entered version: '%cd /' will be seen as
40 history instead of the user-entered version: '%cd /' will be seen as
41 '_ip.magic("%cd /")' instead of '%cd /'.
41 '_ip.magic("%cd /")' instead of '%cd /'.
42
42
43 -r: print the 'raw' history, i.e. the actual commands you typed.
43 -r: print the 'raw' history, i.e. the actual commands you typed.
44
44
45 -g: treat the arg as a pattern to grep for in (full) history.
45 -g: treat the arg as a pattern to grep for in (full) history.
46 This includes the "shadow history" (almost all commands ever written).
46 This includes the "shadow history" (almost all commands ever written).
47 Use '%hist -g' to show full shadow history (may be very long).
47 Use '%hist -g' to show full shadow history (may be very long).
48 In shadow history, every index nuwber starts with 0.
48 In shadow history, every index nuwber starts with 0.
49
49
50 -f FILENAME: instead of printing the output to the screen, redirect it to
50 -f FILENAME: instead of printing the output to the screen, redirect it to
51 the given file. The file is always overwritten, though IPython asks for
51 the given file. The file is always overwritten, though IPython asks for
52 confirmation first if it already exists.
52 confirmation first if it already exists.
53 """
53 """
54
54
55 if not self.outputcache.do_full_cache:
55 if not self.outputcache.do_full_cache:
56 print 'This feature is only available if numbered prompts are in use.'
56 print 'This feature is only available if numbered prompts are in use.'
57 return
57 return
58 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
58 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
59
59
60 # Check if output to specific file was requested.
60 # Check if output to specific file was requested.
61 try:
61 try:
62 outfname = opts['f']
62 outfname = opts['f']
63 except KeyError:
63 except KeyError:
64 outfile = Term.cout # default
64 outfile = Term.cout # default
65 # We don't want to close stdout at the end!
65 # We don't want to close stdout at the end!
66 close_at_end = False
66 close_at_end = False
67 else:
67 else:
68 if os.path.exists(outfname):
68 if os.path.exists(outfname):
69 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
69 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
70 print 'Aborting.'
70 print 'Aborting.'
71 return
71 return
72
72
73 outfile = open(outfname,'w')
73 outfile = open(outfname,'w')
74 close_at_end = True
74 close_at_end = True
75
75
76 if 't' in opts:
76 if 't' in opts:
77 input_hist = self.input_hist
77 input_hist = self.input_hist
78 elif 'r' in opts:
78 elif 'r' in opts:
79 input_hist = self.input_hist_raw
79 input_hist = self.input_hist_raw
80 else:
80 else:
81 input_hist = self.input_hist
81 input_hist = self.input_hist
82
82
83 default_length = 40
83 default_length = 40
84 pattern = None
84 pattern = None
85 if 'g' in opts:
85 if 'g' in opts:
86 init = 1
86 init = 1
87 final = len(input_hist)
87 final = len(input_hist)
88 parts = parameter_s.split(None,1)
88 parts = parameter_s.split(None, 1)
89 if len(parts) == 1:
89 if len(parts) == 1:
90 parts += '*'
90 parts += '*'
91 head, pattern = parts
91 head, pattern = parts
92 pattern = "*" + pattern + "*"
92 pattern = "*" + pattern + "*"
93 elif len(args) == 0:
93 elif len(args) == 0:
94 final = len(input_hist)
94 final = len(input_hist)-1
95 init = max(1,final-default_length)
95 init = max(1,final-default_length)
96 elif len(args) == 1:
96 elif len(args) == 1:
97 final = len(input_hist)
97 final = len(input_hist)
98 init = max(1,final-int(args[0]))
98 init = max(1, final-int(args[0]))
99 elif len(args) == 2:
99 elif len(args) == 2:
100 init,final = map(int,args)
100 init, final = map(int, args)
101 else:
101 else:
102 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
102 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
103 print self.magic_hist.__doc__
103 print >> Term.cout, self.magic_hist.__doc__
104 return
104 return
105
105
106 width = len(str(final))
106 width = len(str(final))
107 line_sep = ['','\n']
107 line_sep = ['','\n']
108 print_nums = 'n' in opts
108 print_nums = 'n' in opts
109 print_outputs = 'o' in opts
109 print_outputs = 'o' in opts
110 pyprompts = 'p' in opts
110 pyprompts = 'p' in opts
111
111
112 found = False
112 found = False
113 if pattern is not None:
113 if pattern is not None:
114 sh = self.shadowhist.all()
114 sh = self.shadowhist.all()
115 for idx, s in sh:
115 for idx, s in sh:
116 if fnmatch.fnmatch(s, pattern):
116 if fnmatch.fnmatch(s, pattern):
117 print "0%d: %s" %(idx, s)
117 print >> outfile, "0%d: %s" %(idx, s)
118 found = True
118 found = True
119
119
120 if found:
120 if found:
121 print "==="
121 print >> outfile, "==="
122 print "shadow history ends, fetch by %rep <number> (must start with 0)"
122 print >> outfile, \
123 print "=== start of normal history ==="
123 "shadow history ends, fetch by %rep <number> (must start with 0)"
124 print >> outfile, "=== start of normal history ==="
124
125
125 for in_num in range(init,final):
126 for in_num in range(init,final):
126 inline = input_hist[in_num]
127 inline = input_hist[in_num]
127 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
128 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
128 continue
129 continue
129
130
130 multiline = int(inline.count('\n') > 1)
131 multiline = int(inline.count('\n') > 1)
131 if print_nums:
132 if print_nums:
132 print >> outfile, \
133 print >> outfile, \
133 '%s:%s' % (str(in_num).ljust(width),line_sep[multiline]),
134 '%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
134 if pyprompts:
135 if pyprompts:
135 print >> outfile, '>>>',
136 print >> outfile, '>>>',
136 if multiline:
137 if multiline:
137 lines = inline.splitlines()
138 lines = inline.splitlines()
138 print >> outfile, '\n... '.join(lines)
139 print >> outfile, '\n... '.join(lines)
139 print >> outfile, '... '
140 print >> outfile, '... '
140 else:
141 else:
141 print >> outfile, inline,
142 print >> outfile, inline,
142 else:
143 else:
143 print >> outfile, inline,
144 print >> outfile, inline,
145 if print_outputs:
144 output = self.shell.user_ns['Out'].get(in_num)
146 output = self.shell.user_ns['Out'].get(in_num)
145 if output is not None:
147 if output is not None:
146 print repr(output)
148 print >> outfile, repr(output)
147
149
148 if close_at_end:
150 if close_at_end:
149 outfile.close()
151 outfile.close()
150
152
151
153
152 def magic_hist(self, parameter_s=''):
154 def magic_hist(self, parameter_s=''):
153 """Alternate name for %history."""
155 """Alternate name for %history."""
154 return self.magic_history(parameter_s)
156 return self.magic_history(parameter_s)
155
157
156
158
157 def rep_f(self, arg):
159 def rep_f(self, arg):
158 r""" Repeat a command, or get command to input line for editing
160 r""" Repeat a command, or get command to input line for editing
159
161
160 - %rep (no arguments):
162 - %rep (no arguments):
161
163
162 Place a string version of last computation result (stored in the special '_'
164 Place a string version of last computation result (stored in the special '_'
163 variable) to the next input prompt. Allows you to create elaborate command
165 variable) to the next input prompt. Allows you to create elaborate command
164 lines without using copy-paste::
166 lines without using copy-paste::
165
167
166 $ l = ["hei", "vaan"]
168 $ l = ["hei", "vaan"]
167 $ "".join(l)
169 $ "".join(l)
168 ==> heivaan
170 ==> heivaan
169 $ %rep
171 $ %rep
170 $ heivaan_ <== cursor blinking
172 $ heivaan_ <== cursor blinking
171
173
172 %rep 45
174 %rep 45
173
175
174 Place history line 45 to next input prompt. Use %hist to find out the
176 Place history line 45 to next input prompt. Use %hist to find out the
175 number.
177 number.
176
178
177 %rep 1-4 6-7 3
179 %rep 1-4 6-7 3
178
180
179 Repeat the specified lines immediately. Input slice syntax is the same as
181 Repeat the specified lines immediately. Input slice syntax is the same as
180 in %macro and %save.
182 in %macro and %save.
181
183
182 %rep foo
184 %rep foo
183
185
184 Place the most recent line that has the substring "foo" to next input.
186 Place the most recent line that has the substring "foo" to next input.
185 (e.g. 'svn ci -m foobar').
187 (e.g. 'svn ci -m foobar').
186 """
188 """
187
189
188 opts,args = self.parse_options(arg,'',mode='list')
190 opts,args = self.parse_options(arg,'',mode='list')
189 if not args:
191 if not args:
190 self.set_next_input(str(self.user_ns["_"]))
192 self.set_next_input(str(self.user_ns["_"]))
191 return
193 return
192
194
193 if len(args) == 1 and not '-' in args[0]:
195 if len(args) == 1 and not '-' in args[0]:
194 arg = args[0]
196 arg = args[0]
195 if len(arg) > 1 and arg.startswith('0'):
197 if len(arg) > 1 and arg.startswith('0'):
196 # get from shadow hist
198 # get from shadow hist
197 num = int(arg[1:])
199 num = int(arg[1:])
198 line = self.shadowhist.get(num)
200 line = self.shadowhist.get(num)
199 self.set_next_input(str(line))
201 self.set_next_input(str(line))
200 return
202 return
201 try:
203 try:
202 num = int(args[0])
204 num = int(args[0])
203 self.set_next_input(str(self.input_hist_raw[num]).rstrip())
205 self.set_next_input(str(self.input_hist_raw[num]).rstrip())
204 return
206 return
205 except ValueError:
207 except ValueError:
206 pass
208 pass
207
209
208 for h in reversed(self.input_hist_raw):
210 for h in reversed(self.input_hist_raw):
209 if 'rep' in h:
211 if 'rep' in h:
210 continue
212 continue
211 if fnmatch.fnmatch(h,'*' + arg + '*'):
213 if fnmatch.fnmatch(h,'*' + arg + '*'):
212 self.set_next_input(str(h).rstrip())
214 self.set_next_input(str(h).rstrip())
213 return
215 return
214
216
215 try:
217 try:
216 lines = self.extract_input_slices(args, True)
218 lines = self.extract_input_slices(args, True)
217 print "lines",lines
219 print "lines",lines
218 self.runlines(lines)
220 self.runlines(lines)
219 except ValueError:
221 except ValueError:
220 print "Not found in recent history:", args
222 print "Not found in recent history:", args
221
223
222
224
223 _sentinel = object()
225 _sentinel = object()
224
226
225 class ShadowHist(object):
227 class ShadowHist(object):
226 def __init__(self,db):
228 def __init__(self,db):
227 # cmd => idx mapping
229 # cmd => idx mapping
228 self.curidx = 0
230 self.curidx = 0
229 self.db = db
231 self.db = db
230 self.disabled = False
232 self.disabled = False
231
233
232 def inc_idx(self):
234 def inc_idx(self):
233 idx = self.db.get('shadowhist_idx', 1)
235 idx = self.db.get('shadowhist_idx', 1)
234 self.db['shadowhist_idx'] = idx + 1
236 self.db['shadowhist_idx'] = idx + 1
235 return idx
237 return idx
236
238
237 def add(self, ent):
239 def add(self, ent):
238 if self.disabled:
240 if self.disabled:
239 return
241 return
240 try:
242 try:
241 old = self.db.hget('shadowhist', ent, _sentinel)
243 old = self.db.hget('shadowhist', ent, _sentinel)
242 if old is not _sentinel:
244 if old is not _sentinel:
243 return
245 return
244 newidx = self.inc_idx()
246 newidx = self.inc_idx()
245 #print "new",newidx # dbg
247 #print "new",newidx # dbg
246 self.db.hset('shadowhist',ent, newidx)
248 self.db.hset('shadowhist',ent, newidx)
247 except:
249 except:
248 ipapi.get().showtraceback()
250 ipapi.get().showtraceback()
249 print "WARNING: disabling shadow history"
251 print "WARNING: disabling shadow history"
250 self.disabled = True
252 self.disabled = True
251
253
252 def all(self):
254 def all(self):
253 d = self.db.hdict('shadowhist')
255 d = self.db.hdict('shadowhist')
254 items = [(i,s) for (s,i) in d.items()]
256 items = [(i,s) for (s,i) in d.items()]
255 items.sort()
257 items.sort()
256 return items
258 return items
257
259
258 def get(self, idx):
260 def get(self, idx):
259 all = self.all()
261 all = self.all()
260
262
261 for k, v in all:
263 for k, v in all:
262 #print k,v
264 #print k,v
263 if k == idx:
265 if k == idx:
264 return v
266 return v
265
267
266
268
267 def init_ipython(ip):
269 def init_ipython(ip):
268 ip.define_magic("rep",rep_f)
270 ip.define_magic("rep",rep_f)
269 ip.define_magic("hist",magic_hist)
271 ip.define_magic("hist",magic_hist)
270 ip.define_magic("history",magic_history)
272 ip.define_magic("history",magic_history)
271
273
272 # XXX - ipy_completers are in quarantine, need to be updated to new apis
274 # XXX - ipy_completers are in quarantine, need to be updated to new apis
273 #import ipy_completers
275 #import ipy_completers
274 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
276 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
@@ -1,279 +1,278 b''
1 """Tests for various magic functions.
1 """Tests for various magic functions.
2
2
3 Needs to be run by nose (to make ipython session available).
3 Needs to be run by nose (to make ipython session available).
4 """
4 """
5 from __future__ import absolute_import
5 from __future__ import absolute_import
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Imports
8 # Imports
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 # stdlib
11 # stdlib
12 import os
12 import os
13 import sys
13 import sys
14 import tempfile
14 import tempfile
15 import types
15 import types
16 from cStringIO import StringIO
16 from cStringIO import StringIO
17
17
18 # third-party
18 # third-party
19 import nose.tools as nt
19 import nose.tools as nt
20
20
21 # our own
21 # our own
22 from IPython.utils import genutils
22 from IPython.utils import genutils
23 from IPython.utils.platutils import find_cmd, get_long_path_name
23 from IPython.utils.platutils import find_cmd, get_long_path_name
24 from IPython.testing import decorators as dec
24 from IPython.testing import decorators as dec
25 from IPython.testing import tools as tt
25 from IPython.testing import tools as tt
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Test functions begin
28 # Test functions begin
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 def test_rehashx():
30 def test_rehashx():
31 # clear up everything
31 # clear up everything
32 _ip = get_ipython()
32 _ip = get_ipython()
33 _ip.alias_manager.alias_table.clear()
33 _ip.alias_manager.alias_table.clear()
34 del _ip.db['syscmdlist']
34 del _ip.db['syscmdlist']
35
35
36 _ip.magic('rehashx')
36 _ip.magic('rehashx')
37 # Practically ALL ipython development systems will have more than 10 aliases
37 # Practically ALL ipython development systems will have more than 10 aliases
38
38
39 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
39 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
40 for key, val in _ip.alias_manager.alias_table.items():
40 for key, val in _ip.alias_manager.alias_table.items():
41 # we must strip dots from alias names
41 # we must strip dots from alias names
42 nt.assert_true('.' not in key)
42 nt.assert_true('.' not in key)
43
43
44 # rehashx must fill up syscmdlist
44 # rehashx must fill up syscmdlist
45 scoms = _ip.db['syscmdlist']
45 scoms = _ip.db['syscmdlist']
46 yield (nt.assert_true, len(scoms) > 10)
46 yield (nt.assert_true, len(scoms) > 10)
47
47
48
48
49 def test_magic_parse_options():
49 def test_magic_parse_options():
50 """Test that we don't mangle paths when parsing magic options."""
50 """Test that we don't mangle paths when parsing magic options."""
51 ip = get_ipython()
51 ip = get_ipython()
52 path = 'c:\\x'
52 path = 'c:\\x'
53 opts = ip.parse_options('-f %s' % path,'f:')[0]
53 opts = ip.parse_options('-f %s' % path,'f:')[0]
54 # argv splitting is os-dependent
54 # argv splitting is os-dependent
55 if os.name == 'posix':
55 if os.name == 'posix':
56 expected = 'c:x'
56 expected = 'c:x'
57 else:
57 else:
58 expected = path
58 expected = path
59 nt.assert_equals(opts['f'], expected)
59 nt.assert_equals(opts['f'], expected)
60
60
61
61
62 def doctest_hist_f():
62 def doctest_hist_f():
63 """Test %hist -f with temporary filename.
63 """Test %hist -f with temporary filename.
64
64
65 In [9]: import tempfile
65 In [9]: import tempfile
66
66
67 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
67 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
68
68
69 In [11]: %hist -n -f $tfile 3
69 In [11]: %hist -n -f $tfile 3
70
70
71 In [13]: import os; os.unlink(tfile)
71 In [13]: import os; os.unlink(tfile)
72 """
72 """
73
73
74
74
75 def doctest_hist_r():
75 def doctest_hist_r():
76 """Test %hist -r
76 """Test %hist -r
77
77
78 XXX - This test is not recording the output correctly. For some reason, in
78 XXX - This test is not recording the output correctly. For some reason, in
79 testing mode the raw history isn't getting populated. No idea why.
79 testing mode the raw history isn't getting populated. No idea why.
80 Disabling the output checking for now, though at least we do run it.
80 Disabling the output checking for now, though at least we do run it.
81
81
82 In [1]: 'hist' in _ip.lsmagic()
82 In [1]: 'hist' in _ip.lsmagic()
83 Out[1]: True
83 Out[1]: True
84
84
85 In [2]: x=1
85 In [2]: x=1
86
86
87 In [3]: %hist -r 2
87 In [3]: %hist -r 2
88 x=1 # random
88 x=1 # random
89 %hist -r 2
89 %hist -r 2
90 """
90 """
91
91
92 def doctest_hist_op():
92 def doctest_hist_op():
93 """Test %hist -op
93 """Test %hist -op
94
94
95 In [1]: class b:
95 In [1]: class b:
96 ...: pass
96 ...: pass
97 ...:
97 ...:
98
98
99 In [2]: class s(b):
99 In [2]: class s(b):
100 ...: def __str__(self):
100 ...: def __str__(self):
101 ...: return 's'
101 ...: return 's'
102 ...:
102 ...:
103
103
104 In [3]:
104 In [3]:
105
105
106 In [4]: class r(b):
106 In [4]: class r(b):
107 ...: def __repr__(self):
107 ...: def __repr__(self):
108 ...: return 'r'
108 ...: return 'r'
109 ...:
109 ...:
110
110
111 In [5]: class sr(s,r): pass
111 In [5]: class sr(s,r): pass
112 ...:
112 ...:
113
113
114 In [6]:
114 In [6]:
115
115
116 In [7]: bb=b()
116 In [7]: bb=b()
117
117
118 In [8]: ss=s()
118 In [8]: ss=s()
119
119
120 In [9]: rr=r()
120 In [9]: rr=r()
121
121
122 In [10]: ssrr=sr()
122 In [10]: ssrr=sr()
123
123
124 In [11]: bb
124 In [11]: bb
125 Out[11]: <...b instance at ...>
125 Out[11]: <...b instance at ...>
126
126
127 In [12]: ss
127 In [12]: ss
128 Out[12]: <...s instance at ...>
128 Out[12]: <...s instance at ...>
129
129
130 In [13]:
130 In [13]:
131
131
132 In [14]: %hist -op
132 In [14]: %hist -op
133 >>> class b:
133 >>> class b:
134 ... pass
134 ... pass
135 ...
135 ...
136 >>> class s(b):
136 >>> class s(b):
137 ... def __str__(self):
137 ... def __str__(self):
138 ... return 's'
138 ... return 's'
139 ...
139 ...
140 >>>
140 >>>
141 >>> class r(b):
141 >>> class r(b):
142 ... def __repr__(self):
142 ... def __repr__(self):
143 ... return 'r'
143 ... return 'r'
144 ...
144 ...
145 >>> class sr(s,r): pass
145 >>> class sr(s,r): pass
146 >>>
146 >>>
147 >>> bb=b()
147 >>> bb=b()
148 >>> ss=s()
148 >>> ss=s()
149 >>> rr=r()
149 >>> rr=r()
150 >>> ssrr=sr()
150 >>> ssrr=sr()
151 >>> bb
151 >>> bb
152 <...b instance at ...>
152 <...b instance at ...>
153 >>> ss
153 >>> ss
154 <...s instance at ...>
154 <...s instance at ...>
155 >>>
155 >>>
156 >>> get_ipython().magic("hist -op")
157 """
156 """
158
157
159 def test_shist():
158 def test_shist():
160 # Simple tests of ShadowHist class - test generator.
159 # Simple tests of ShadowHist class - test generator.
161 import os, shutil, tempfile
160 import os, shutil, tempfile
162
161
163 from IPython.utils import pickleshare
162 from IPython.utils import pickleshare
164 from IPython.core.history import ShadowHist
163 from IPython.core.history import ShadowHist
165
164
166 tfile = tempfile.mktemp('','tmp-ipython-')
165 tfile = tempfile.mktemp('','tmp-ipython-')
167
166
168 db = pickleshare.PickleShareDB(tfile)
167 db = pickleshare.PickleShareDB(tfile)
169 s = ShadowHist(db)
168 s = ShadowHist(db)
170 s.add('hello')
169 s.add('hello')
171 s.add('world')
170 s.add('world')
172 s.add('hello')
171 s.add('hello')
173 s.add('hello')
172 s.add('hello')
174 s.add('karhu')
173 s.add('karhu')
175
174
176 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
175 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
177
176
178 yield nt.assert_equal,s.get(2),'world'
177 yield nt.assert_equal,s.get(2),'world'
179
178
180 shutil.rmtree(tfile)
179 shutil.rmtree(tfile)
181
180
182
181
183 # XXX failing for now, until we get clearcmd out of quarantine. But we should
182 # XXX failing for now, until we get clearcmd out of quarantine. But we should
184 # fix this and revert the skip to happen only if numpy is not around.
183 # fix this and revert the skip to happen only if numpy is not around.
185 #@dec.skipif_not_numpy
184 #@dec.skipif_not_numpy
186 @dec.skipknownfailure
185 @dec.skipknownfailure
187 def test_numpy_clear_array_undec():
186 def test_numpy_clear_array_undec():
188 from IPython.extensions import clearcmd
187 from IPython.extensions import clearcmd
189
188
190 _ip.ex('import numpy as np')
189 _ip.ex('import numpy as np')
191 _ip.ex('a = np.empty(2)')
190 _ip.ex('a = np.empty(2)')
192 yield (nt.assert_true, 'a' in _ip.user_ns)
191 yield (nt.assert_true, 'a' in _ip.user_ns)
193 _ip.magic('clear array')
192 _ip.magic('clear array')
194 yield (nt.assert_false, 'a' in _ip.user_ns)
193 yield (nt.assert_false, 'a' in _ip.user_ns)
195
194
196
195
197 # Multiple tests for clipboard pasting
196 # Multiple tests for clipboard pasting
198 @dec.parametric
197 @dec.parametric
199 def test_paste():
198 def test_paste():
200 _ip = get_ipython()
199 _ip = get_ipython()
201 def paste(txt, flags='-q'):
200 def paste(txt, flags='-q'):
202 """Paste input text, by default in quiet mode"""
201 """Paste input text, by default in quiet mode"""
203 hooks.clipboard_get = lambda : txt
202 hooks.clipboard_get = lambda : txt
204 _ip.magic('paste '+flags)
203 _ip.magic('paste '+flags)
205
204
206 # Inject fake clipboard hook but save original so we can restore it later
205 # Inject fake clipboard hook but save original so we can restore it later
207 hooks = _ip.hooks
206 hooks = _ip.hooks
208 user_ns = _ip.user_ns
207 user_ns = _ip.user_ns
209 original_clip = hooks.clipboard_get
208 original_clip = hooks.clipboard_get
210
209
211 try:
210 try:
212 # This try/except with an emtpy except clause is here only because
211 # This try/except with an emtpy except clause is here only because
213 # try/yield/finally is invalid syntax in Python 2.4. This will be
212 # try/yield/finally is invalid syntax in Python 2.4. This will be
214 # removed when we drop 2.4-compatibility, and the emtpy except below
213 # removed when we drop 2.4-compatibility, and the emtpy except below
215 # will be changed to a finally.
214 # will be changed to a finally.
216
215
217 # Run tests with fake clipboard function
216 # Run tests with fake clipboard function
218 user_ns.pop('x', None)
217 user_ns.pop('x', None)
219 paste('x=1')
218 paste('x=1')
220 yield nt.assert_equal(user_ns['x'], 1)
219 yield nt.assert_equal(user_ns['x'], 1)
221
220
222 user_ns.pop('x', None)
221 user_ns.pop('x', None)
223 paste('>>> x=2')
222 paste('>>> x=2')
224 yield nt.assert_equal(user_ns['x'], 2)
223 yield nt.assert_equal(user_ns['x'], 2)
225
224
226 paste("""
225 paste("""
227 >>> x = [1,2,3]
226 >>> x = [1,2,3]
228 >>> y = []
227 >>> y = []
229 >>> for i in x:
228 >>> for i in x:
230 ... y.append(i**2)
229 ... y.append(i**2)
231 ...
230 ...
232 """)
231 """)
233 yield nt.assert_equal(user_ns['x'], [1,2,3])
232 yield nt.assert_equal(user_ns['x'], [1,2,3])
234 yield nt.assert_equal(user_ns['y'], [1,4,9])
233 yield nt.assert_equal(user_ns['y'], [1,4,9])
235
234
236 # Now, test that paste -r works
235 # Now, test that paste -r works
237 user_ns.pop('x', None)
236 user_ns.pop('x', None)
238 yield nt.assert_false('x' in user_ns)
237 yield nt.assert_false('x' in user_ns)
239 _ip.magic('paste -r')
238 _ip.magic('paste -r')
240 yield nt.assert_equal(user_ns['x'], [1,2,3])
239 yield nt.assert_equal(user_ns['x'], [1,2,3])
241
240
242 # Also test paste echoing, by temporarily faking the writer
241 # Also test paste echoing, by temporarily faking the writer
243 w = StringIO()
242 w = StringIO()
244 writer = _ip.write
243 writer = _ip.write
245 _ip.write = w.write
244 _ip.write = w.write
246 code = """
245 code = """
247 a = 100
246 a = 100
248 b = 200"""
247 b = 200"""
249 try:
248 try:
250 paste(code,'')
249 paste(code,'')
251 out = w.getvalue()
250 out = w.getvalue()
252 finally:
251 finally:
253 _ip.write = writer
252 _ip.write = writer
254 yield nt.assert_equal(user_ns['a'], 100)
253 yield nt.assert_equal(user_ns['a'], 100)
255 yield nt.assert_equal(user_ns['b'], 200)
254 yield nt.assert_equal(user_ns['b'], 200)
256 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
255 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
257
256
258 finally:
257 finally:
259 # This should be in a finally clause, instead of the bare except above.
258 # This should be in a finally clause, instead of the bare except above.
260 # Restore original hook
259 # Restore original hook
261 hooks.clipboard_get = original_clip
260 hooks.clipboard_get = original_clip
262
261
263
262
264 def test_time():
263 def test_time():
265 _ip.magic('time None')
264 _ip.magic('time None')
266
265
267
266
268 def doctest_time():
267 def doctest_time():
269 """
268 """
270 In [10]: %time None
269 In [10]: %time None
271 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
270 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
272 Wall time: 0.00 s
271 Wall time: 0.00 s
273 """
272 """
274
273
275 def test_doctest_mode():
274 def test_doctest_mode():
276 "Toggle doctest_mode twice, it should be a no-op and run without error"
275 "Toggle doctest_mode twice, it should be a no-op and run without error"
277 _ip.magic('doctest_mode')
276 _ip.magic('doctest_mode')
278 _ip.magic('doctest_mode')
277 _ip.magic('doctest_mode')
279
278
General Comments 0
You need to be logged in to leave comments. Login now