##// END OF EJS Templates
Merge pull request #5841 from takluyver/i2412...
Min RK -
r16724:6fa735fb merge
parent child Browse files
Show More
@@ -1,318 +1,319
1 1 """Implementation of magic functions related to History.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012, IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 # Stdlib
17 17 import os
18 18 from io import open as io_open
19 19
20 20 # Our own packages
21 21 from IPython.core.error import StdinNotImplementedError
22 22 from IPython.core.magic import Magics, magics_class, line_magic
23 23 from IPython.core.magic_arguments import (argument, magic_arguments,
24 24 parse_argstring)
25 25 from IPython.testing.skipdoctest import skip_doctest
26 26 from IPython.utils import io
27 from IPython.utils.py3compat import cast_unicode_py2
27 28
28 29 #-----------------------------------------------------------------------------
29 30 # Magics class implementation
30 31 #-----------------------------------------------------------------------------
31 32
32 33
33 34 _unspecified = object()
34 35
35 36
36 37 @magics_class
37 38 class HistoryMagics(Magics):
38 39
39 40 @magic_arguments()
40 41 @argument(
41 42 '-n', dest='print_nums', action='store_true', default=False,
42 43 help="""
43 44 print line numbers for each input.
44 45 This feature is only available if numbered prompts are in use.
45 46 """)
46 47 @argument(
47 48 '-o', dest='get_output', action='store_true', default=False,
48 49 help="also print outputs for each input.")
49 50 @argument(
50 51 '-p', dest='pyprompts', action='store_true', default=False,
51 52 help="""
52 53 print classic '>>>' python prompts before each input.
53 54 This is useful for making documentation, and in conjunction
54 55 with -o, for producing doctest-ready output.
55 56 """)
56 57 @argument(
57 58 '-t', dest='raw', action='store_false', default=True,
58 59 help="""
59 60 print the 'translated' history, as IPython understands it.
60 61 IPython filters your input and converts it all into valid Python
61 62 source before executing it (things like magics or aliases are turned
62 63 into function calls, for example). With this option, you'll see the
63 64 native history instead of the user-entered version: '%%cd /' will be
64 65 seen as 'get_ipython().magic("%%cd /")' instead of '%%cd /'.
65 66 """)
66 67 @argument(
67 68 '-f', dest='filename',
68 69 help="""
69 70 FILENAME: instead of printing the output to the screen, redirect
70 71 it to the given file. The file is always overwritten, though *when
71 72 it can*, IPython asks for confirmation first. In particular, running
72 73 the command 'history -f FILENAME' from the IPython Notebook
73 74 interface will replace FILENAME even if it already exists *without*
74 75 confirmation.
75 76 """)
76 77 @argument(
77 78 '-g', dest='pattern', nargs='*', default=None,
78 79 help="""
79 80 treat the arg as a glob pattern to search for in (full) history.
80 81 This includes the saved history (almost all commands ever written).
81 82 The pattern may contain '?' to match one unknown character and '*'
82 83 to match any number of unknown characters. Use '%%hist -g' to show
83 84 full saved history (may be very long).
84 85 """)
85 86 @argument(
86 87 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
87 88 help="""
88 89 get the last n lines from all sessions. Specify n as a single
89 90 arg, or the default is the last 10 lines.
90 91 """)
91 92 @argument(
92 93 '-u', dest='unique', action='store_true',
93 94 help="""
94 95 when searching history using `-g`, show only unique history.
95 96 """)
96 97 @argument('range', nargs='*')
97 98 @skip_doctest
98 99 @line_magic
99 100 def history(self, parameter_s = ''):
100 101 """Print input history (_i<n> variables), with most recent last.
101 102
102 103 By default, input history is printed without line numbers so it can be
103 104 directly pasted into an editor. Use -n to show them.
104 105
105 106 By default, all input history from the current session is displayed.
106 107 Ranges of history can be indicated using the syntax:
107 108
108 109 ``4``
109 110 Line 4, current session
110 111 ``4-6``
111 112 Lines 4-6, current session
112 113 ``243/1-5``
113 114 Lines 1-5, session 243
114 115 ``~2/7``
115 116 Line 7, session 2 before current
116 117 ``~8/1-~6/5``
117 118 From the first line of 8 sessions ago, to the fifth line of 6
118 119 sessions ago.
119 120
120 121 Multiple ranges can be entered, separated by spaces
121 122
122 123 The same syntax is used by %macro, %save, %edit, %rerun
123 124
124 125 Examples
125 126 --------
126 127 ::
127 128
128 129 In [6]: %history -n 4-6
129 130 4:a = 12
130 131 5:print a**2
131 132 6:%history -n 4-6
132 133
133 134 """
134 135
135 136 args = parse_argstring(self.history, parameter_s)
136 137
137 138 # For brevity
138 139 history_manager = self.shell.history_manager
139 140
140 141 def _format_lineno(session, line):
141 142 """Helper function to format line numbers properly."""
142 143 if session in (0, history_manager.session_number):
143 144 return str(line)
144 145 return "%s/%s" % (session, line)
145 146
146 147 # Check if output to specific file was requested.
147 148 outfname = args.filename
148 149 if not outfname:
149 150 outfile = io.stdout # default
150 151 # We don't want to close stdout at the end!
151 152 close_at_end = False
152 153 else:
153 154 if os.path.exists(outfname):
154 155 try:
155 156 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
156 157 except StdinNotImplementedError:
157 158 ans = True
158 159 if not ans:
159 160 print('Aborting.')
160 161 return
161 162 print("Overwriting file.")
162 163 outfile = io_open(outfname, 'w', encoding='utf-8')
163 164 close_at_end = True
164 165
165 166 print_nums = args.print_nums
166 167 get_output = args.get_output
167 168 pyprompts = args.pyprompts
168 169 raw = args.raw
169 170
170 171 pattern = None
171 172 limit = None if args.limit is _unspecified else args.limit
172 173
173 174 if args.pattern is not None:
174 175 if args.pattern:
175 176 pattern = "*" + " ".join(args.pattern) + "*"
176 177 else:
177 178 pattern = "*"
178 179 hist = history_manager.search(pattern, raw=raw, output=get_output,
179 180 n=limit, unique=args.unique)
180 181 print_nums = True
181 182 elif args.limit is not _unspecified:
182 183 n = 10 if limit is None else limit
183 184 hist = history_manager.get_tail(n, raw=raw, output=get_output)
184 185 else:
185 186 if args.range: # Get history by ranges
186 187 hist = history_manager.get_range_by_str(" ".join(args.range),
187 188 raw, get_output)
188 189 else: # Just get history for the current session
189 190 hist = history_manager.get_range(raw=raw, output=get_output)
190 191
191 192 # We could be displaying the entire history, so let's not try to pull
192 193 # it into a list in memory. Anything that needs more space will just
193 194 # misalign.
194 195 width = 4
195 196
196 197 for session, lineno, inline in hist:
197 198 # Print user history with tabs expanded to 4 spaces. The GUI
198 199 # clients use hard tabs for easier usability in auto-indented code,
199 200 # but we want to produce PEP-8 compliant history for safe pasting
200 201 # into an editor.
201 202 if get_output:
202 203 inline, output = inline
203 204 inline = inline.expandtabs(4).rstrip()
204 205
205 206 multiline = "\n" in inline
206 207 line_sep = '\n' if multiline else ' '
207 208 if print_nums:
208 209 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
209 210 line_sep), file=outfile, end=u'')
210 211 if pyprompts:
211 212 print(u">>> ", end=u"", file=outfile)
212 213 if multiline:
213 214 inline = "\n... ".join(inline.splitlines()) + "\n..."
214 215 print(inline, file=outfile)
215 216 if get_output and output:
216 print(output, file=outfile)
217 print(cast_unicode_py2(output), file=outfile)
217 218
218 219 if close_at_end:
219 220 outfile.close()
220 221
221 222 @line_magic
222 223 def recall(self, arg):
223 224 r"""Repeat a command, or get command to input line for editing.
224 225
225 226 %recall and %rep are equivalent.
226 227
227 228 - %recall (no arguments):
228 229
229 230 Place a string version of last computation result (stored in the
230 231 special '_' variable) to the next input prompt. Allows you to create
231 232 elaborate command lines without using copy-paste::
232 233
233 234 In[1]: l = ["hei", "vaan"]
234 235 In[2]: "".join(l)
235 236 Out[2]: heivaan
236 237 In[3]: %recall
237 238 In[4]: heivaan_ <== cursor blinking
238 239
239 240 %recall 45
240 241
241 242 Place history line 45 on the next input prompt. Use %hist to find
242 243 out the number.
243 244
244 245 %recall 1-4
245 246
246 247 Combine the specified lines into one cell, and place it on the next
247 248 input prompt. See %history for the slice syntax.
248 249
249 250 %recall foo+bar
250 251
251 252 If foo+bar can be evaluated in the user namespace, the result is
252 253 placed at the next input prompt. Otherwise, the history is searched
253 254 for lines which contain that substring, and the most recent one is
254 255 placed at the next input prompt.
255 256 """
256 257 if not arg: # Last output
257 258 self.shell.set_next_input(str(self.shell.user_ns["_"]))
258 259 return
259 260 # Get history range
260 261 histlines = self.shell.history_manager.get_range_by_str(arg)
261 262 cmd = "\n".join(x[2] for x in histlines)
262 263 if cmd:
263 264 self.shell.set_next_input(cmd.rstrip())
264 265 return
265 266
266 267 try: # Variable in user namespace
267 268 cmd = str(eval(arg, self.shell.user_ns))
268 269 except Exception: # Search for term in history
269 270 histlines = self.shell.history_manager.search("*"+arg+"*")
270 271 for h in reversed([x[2] for x in histlines]):
271 272 if 'recall' in h or 'rep' in h:
272 273 continue
273 274 self.shell.set_next_input(h.rstrip())
274 275 return
275 276 else:
276 277 self.shell.set_next_input(cmd.rstrip())
277 278 print("Couldn't evaluate or find in history:", arg)
278 279
279 280 @line_magic
280 281 def rerun(self, parameter_s=''):
281 282 """Re-run previous input
282 283
283 284 By default, you can specify ranges of input history to be repeated
284 285 (as with %history). With no arguments, it will repeat the last line.
285 286
286 287 Options:
287 288
288 289 -l <n> : Repeat the last n lines of input, not including the
289 290 current command.
290 291
291 292 -g foo : Repeat the most recent line which contains foo
292 293 """
293 294 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
294 295 if "l" in opts: # Last n lines
295 296 n = int(opts['l'])
296 297 hist = self.shell.history_manager.get_tail(n)
297 298 elif "g" in opts: # Search
298 299 p = "*"+opts['g']+"*"
299 300 hist = list(self.shell.history_manager.search(p))
300 301 for l in reversed(hist):
301 302 if "rerun" not in l[2]:
302 303 hist = [l] # The last match which isn't a %rerun
303 304 break
304 305 else:
305 306 hist = [] # No matches except %rerun
306 307 elif args: # Specify history ranges
307 308 hist = self.shell.history_manager.get_range_by_str(args)
308 309 else: # Last line
309 310 hist = self.shell.history_manager.get_tail(1)
310 311 hist = [x[2] for x in hist]
311 312 if not hist:
312 313 print("No lines in history match specification")
313 314 return
314 315 histlines = "\n".join(hist)
315 316 print("=== Executing: ===")
316 317 print(histlines)
317 318 print("=== Output: ===")
318 319 self.shell.run_cell("\n".join(hist), store_history=False)
@@ -1,951 +1,961
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions.
3 3
4 4 Needs to be run by nose (to make ipython session available).
5 5 """
6 6 from __future__ import absolute_import
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Imports
10 10 #-----------------------------------------------------------------------------
11 11
12 12 import io
13 13 import os
14 14 import sys
15 15 from unittest import TestCase
16 16
17 17 try:
18 18 from importlib import invalidate_caches # Required from Python 3.3
19 19 except ImportError:
20 20 def invalidate_caches():
21 21 pass
22 22
23 23 import nose.tools as nt
24 24
25 25 from IPython.core import magic
26 26 from IPython.core.magic import (Magics, magics_class, line_magic,
27 27 cell_magic, line_cell_magic,
28 28 register_line_magic, register_cell_magic,
29 29 register_line_cell_magic)
30 30 from IPython.core.magics import execution, script, code
31 31 from IPython.nbformat.v3.tests.nbexamples import nb0
32 32 from IPython.nbformat import current
33 33 from IPython.testing import decorators as dec
34 34 from IPython.testing import tools as tt
35 35 from IPython.utils import py3compat
36 36 from IPython.utils.io import capture_output
37 37 from IPython.utils.tempdir import TemporaryDirectory
38 38 from IPython.utils.process import find_cmd
39 39
40 40 if py3compat.PY3:
41 41 from io import StringIO
42 42 else:
43 43 from StringIO import StringIO
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Test functions begin
47 47 #-----------------------------------------------------------------------------
48 48
49 49 @magic.magics_class
50 50 class DummyMagics(magic.Magics): pass
51 51
52 52 def test_extract_code_ranges():
53 53 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
54 54 expected = [(0, 1),
55 55 (2, 3),
56 56 (4, 6),
57 57 (6, 9),
58 58 (9, 14),
59 59 (16, None),
60 60 (None, 9),
61 61 (9, None),
62 62 (None, 13),
63 63 (None, None)]
64 64 actual = list(code.extract_code_ranges(instr))
65 65 nt.assert_equal(actual, expected)
66 66
67 67 def test_extract_symbols():
68 68 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
69 69 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
70 70 expected = [([], ['a']),
71 71 (["def b():\n return 42\n"], []),
72 72 (["class A: pass\n"], []),
73 73 (["class A: pass\n", "def b():\n return 42\n"], []),
74 74 (["class A: pass\n"], ['a']),
75 75 ([], ['z'])]
76 76 for symbols, exp in zip(symbols_args, expected):
77 77 nt.assert_equal(code.extract_symbols(source, symbols), exp)
78 78
79 79
80 80 def test_extract_symbols_raises_exception_with_non_python_code():
81 81 source = ("=begin A Ruby program :)=end\n"
82 82 "def hello\n"
83 83 "puts 'Hello world'\n"
84 84 "end")
85 85 with nt.assert_raises(SyntaxError):
86 86 code.extract_symbols(source, "hello")
87 87
88 88 def test_config():
89 89 """ test that config magic does not raise
90 90 can happen if Configurable init is moved too early into
91 91 Magics.__init__ as then a Config object will be registerd as a
92 92 magic.
93 93 """
94 94 ## should not raise.
95 95 _ip.magic('config')
96 96
97 97 def test_rehashx():
98 98 # clear up everything
99 99 _ip = get_ipython()
100 100 _ip.alias_manager.clear_aliases()
101 101 del _ip.db['syscmdlist']
102 102
103 103 _ip.magic('rehashx')
104 104 # Practically ALL ipython development systems will have more than 10 aliases
105 105
106 106 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
107 107 for name, cmd in _ip.alias_manager.aliases:
108 108 # we must strip dots from alias names
109 109 nt.assert_not_in('.', name)
110 110
111 111 # rehashx must fill up syscmdlist
112 112 scoms = _ip.db['syscmdlist']
113 113 nt.assert_true(len(scoms) > 10)
114 114
115 115
116 116 def test_magic_parse_options():
117 117 """Test that we don't mangle paths when parsing magic options."""
118 118 ip = get_ipython()
119 119 path = 'c:\\x'
120 120 m = DummyMagics(ip)
121 121 opts = m.parse_options('-f %s' % path,'f:')[0]
122 122 # argv splitting is os-dependent
123 123 if os.name == 'posix':
124 124 expected = 'c:x'
125 125 else:
126 126 expected = path
127 127 nt.assert_equal(opts['f'], expected)
128 128
129 129 def test_magic_parse_long_options():
130 130 """Magic.parse_options can handle --foo=bar long options"""
131 131 ip = get_ipython()
132 132 m = DummyMagics(ip)
133 133 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
134 134 nt.assert_in('foo', opts)
135 135 nt.assert_in('bar', opts)
136 136 nt.assert_equal(opts['bar'], "bubble")
137 137
138 138
139 139 @dec.skip_without('sqlite3')
140 140 def doctest_hist_f():
141 141 """Test %hist -f with temporary filename.
142 142
143 143 In [9]: import tempfile
144 144
145 145 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
146 146
147 147 In [11]: %hist -nl -f $tfile 3
148 148
149 149 In [13]: import os; os.unlink(tfile)
150 150 """
151 151
152 152
153 153 @dec.skip_without('sqlite3')
154 154 def doctest_hist_r():
155 155 """Test %hist -r
156 156
157 157 XXX - This test is not recording the output correctly. For some reason, in
158 158 testing mode the raw history isn't getting populated. No idea why.
159 159 Disabling the output checking for now, though at least we do run it.
160 160
161 161 In [1]: 'hist' in _ip.lsmagic()
162 162 Out[1]: True
163 163
164 164 In [2]: x=1
165 165
166 166 In [3]: %hist -rl 2
167 167 x=1 # random
168 168 %hist -r 2
169 169 """
170 170
171 171
172 172 @dec.skip_without('sqlite3')
173 173 def doctest_hist_op():
174 174 """Test %hist -op
175 175
176 176 In [1]: class b(float):
177 177 ...: pass
178 178 ...:
179 179
180 180 In [2]: class s(object):
181 181 ...: def __str__(self):
182 182 ...: return 's'
183 183 ...:
184 184
185 185 In [3]:
186 186
187 187 In [4]: class r(b):
188 188 ...: def __repr__(self):
189 189 ...: return 'r'
190 190 ...:
191 191
192 192 In [5]: class sr(s,r): pass
193 193 ...:
194 194
195 195 In [6]:
196 196
197 197 In [7]: bb=b()
198 198
199 199 In [8]: ss=s()
200 200
201 201 In [9]: rr=r()
202 202
203 203 In [10]: ssrr=sr()
204 204
205 205 In [11]: 4.5
206 206 Out[11]: 4.5
207 207
208 208 In [12]: str(ss)
209 209 Out[12]: 's'
210 210
211 211 In [13]:
212 212
213 213 In [14]: %hist -op
214 214 >>> class b:
215 215 ... pass
216 216 ...
217 217 >>> class s(b):
218 218 ... def __str__(self):
219 219 ... return 's'
220 220 ...
221 221 >>>
222 222 >>> class r(b):
223 223 ... def __repr__(self):
224 224 ... return 'r'
225 225 ...
226 226 >>> class sr(s,r): pass
227 227 >>>
228 228 >>> bb=b()
229 229 >>> ss=s()
230 230 >>> rr=r()
231 231 >>> ssrr=sr()
232 232 >>> 4.5
233 233 4.5
234 234 >>> str(ss)
235 235 's'
236 236 >>>
237 237 """
238 238
239 def test_hist_pof():
240 ip = get_ipython()
241 ip.run_cell(u"1+2", store_history=True)
242 #raise Exception(ip.history_manager.session_number)
243 #raise Exception(list(ip.history_manager._get_range_session()))
244 with TemporaryDirectory() as td:
245 tf = os.path.join(td, 'hist.py')
246 ip.run_line_magic('history', '-pof %s' % tf)
247 assert os.path.isfile(tf)
248
239 249
240 250 @dec.skip_without('sqlite3')
241 251 def test_macro():
242 252 ip = get_ipython()
243 253 ip.history_manager.reset() # Clear any existing history.
244 254 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
245 255 for i, cmd in enumerate(cmds, start=1):
246 256 ip.history_manager.store_inputs(i, cmd)
247 257 ip.magic("macro test 1-3")
248 258 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
249 259
250 260 # List macros
251 261 nt.assert_in("test", ip.magic("macro"))
252 262
253 263
254 264 @dec.skip_without('sqlite3')
255 265 def test_macro_run():
256 266 """Test that we can run a multi-line macro successfully."""
257 267 ip = get_ipython()
258 268 ip.history_manager.reset()
259 269 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
260 270 "%macro test 2-3"]
261 271 for cmd in cmds:
262 272 ip.run_cell(cmd, store_history=True)
263 273 nt.assert_equal(ip.user_ns["test"].value,
264 274 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
265 275 with tt.AssertPrints("12"):
266 276 ip.run_cell("test")
267 277 with tt.AssertPrints("13"):
268 278 ip.run_cell("test")
269 279
270 280
271 281 def test_magic_magic():
272 282 """Test %magic"""
273 283 ip = get_ipython()
274 284 with capture_output() as captured:
275 285 ip.magic("magic")
276 286
277 287 stdout = captured.stdout
278 288 nt.assert_in('%magic', stdout)
279 289 nt.assert_in('IPython', stdout)
280 290 nt.assert_in('Available', stdout)
281 291
282 292
283 293 @dec.skipif_not_numpy
284 294 def test_numpy_reset_array_undec():
285 295 "Test '%reset array' functionality"
286 296 _ip.ex('import numpy as np')
287 297 _ip.ex('a = np.empty(2)')
288 298 nt.assert_in('a', _ip.user_ns)
289 299 _ip.magic('reset -f array')
290 300 nt.assert_not_in('a', _ip.user_ns)
291 301
292 302 def test_reset_out():
293 303 "Test '%reset out' magic"
294 304 _ip.run_cell("parrot = 'dead'", store_history=True)
295 305 # test '%reset -f out', make an Out prompt
296 306 _ip.run_cell("parrot", store_history=True)
297 307 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
298 308 _ip.magic('reset -f out')
299 309 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
300 310 nt.assert_equal(len(_ip.user_ns['Out']), 0)
301 311
302 312 def test_reset_in():
303 313 "Test '%reset in' magic"
304 314 # test '%reset -f in'
305 315 _ip.run_cell("parrot", store_history=True)
306 316 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
307 317 _ip.magic('%reset -f in')
308 318 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
309 319 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
310 320
311 321 def test_reset_dhist():
312 322 "Test '%reset dhist' magic"
313 323 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
314 324 _ip.magic('cd ' + os.path.dirname(nt.__file__))
315 325 _ip.magic('cd -')
316 326 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
317 327 _ip.magic('reset -f dhist')
318 328 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
319 329 _ip.run_cell("_dh = [d for d in tmp]") #restore
320 330
321 331 def test_reset_in_length():
322 332 "Test that '%reset in' preserves In[] length"
323 333 _ip.run_cell("print 'foo'")
324 334 _ip.run_cell("reset -f in")
325 335 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
326 336
327 337 def test_tb_syntaxerror():
328 338 """test %tb after a SyntaxError"""
329 339 ip = get_ipython()
330 340 ip.run_cell("for")
331 341
332 342 # trap and validate stdout
333 343 save_stdout = sys.stdout
334 344 try:
335 345 sys.stdout = StringIO()
336 346 ip.run_cell("%tb")
337 347 out = sys.stdout.getvalue()
338 348 finally:
339 349 sys.stdout = save_stdout
340 350 # trim output, and only check the last line
341 351 last_line = out.rstrip().splitlines()[-1].strip()
342 352 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
343 353
344 354
345 355 def test_time():
346 356 ip = get_ipython()
347 357
348 358 with tt.AssertPrints("Wall time: "):
349 359 ip.run_cell("%time None")
350 360
351 361 ip.run_cell("def f(kmjy):\n"
352 362 " %time print (2*kmjy)")
353 363
354 364 with tt.AssertPrints("Wall time: "):
355 365 with tt.AssertPrints("hihi", suppress=False):
356 366 ip.run_cell("f('hi')")
357 367
358 368
359 369 @dec.skip_win32
360 370 def test_time2():
361 371 ip = get_ipython()
362 372
363 373 with tt.AssertPrints("CPU times: user "):
364 374 ip.run_cell("%time None")
365 375
366 376 def test_time3():
367 377 """Erroneous magic function calls, issue gh-3334"""
368 378 ip = get_ipython()
369 379 ip.user_ns.pop('run', None)
370 380
371 381 with tt.AssertNotPrints("not found", channel='stderr'):
372 382 ip.run_cell("%%time\n"
373 383 "run = 0\n"
374 384 "run += 1")
375 385
376 386 def test_doctest_mode():
377 387 "Toggle doctest_mode twice, it should be a no-op and run without error"
378 388 _ip.magic('doctest_mode')
379 389 _ip.magic('doctest_mode')
380 390
381 391
382 392 def test_parse_options():
383 393 """Tests for basic options parsing in magics."""
384 394 # These are only the most minimal of tests, more should be added later. At
385 395 # the very least we check that basic text/unicode calls work OK.
386 396 m = DummyMagics(_ip)
387 397 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
388 398 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
389 399
390 400
391 401 def test_dirops():
392 402 """Test various directory handling operations."""
393 403 # curpath = lambda :os.path.splitdrive(py3compat.getcwd())[1].replace('\\','/')
394 404 curpath = py3compat.getcwd
395 405 startdir = py3compat.getcwd()
396 406 ipdir = os.path.realpath(_ip.ipython_dir)
397 407 try:
398 408 _ip.magic('cd "%s"' % ipdir)
399 409 nt.assert_equal(curpath(), ipdir)
400 410 _ip.magic('cd -')
401 411 nt.assert_equal(curpath(), startdir)
402 412 _ip.magic('pushd "%s"' % ipdir)
403 413 nt.assert_equal(curpath(), ipdir)
404 414 _ip.magic('popd')
405 415 nt.assert_equal(curpath(), startdir)
406 416 finally:
407 417 os.chdir(startdir)
408 418
409 419
410 420 def test_xmode():
411 421 # Calling xmode three times should be a no-op
412 422 xmode = _ip.InteractiveTB.mode
413 423 for i in range(3):
414 424 _ip.magic("xmode")
415 425 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
416 426
417 427 def test_reset_hard():
418 428 monitor = []
419 429 class A(object):
420 430 def __del__(self):
421 431 monitor.append(1)
422 432 def __repr__(self):
423 433 return "<A instance>"
424 434
425 435 _ip.user_ns["a"] = A()
426 436 _ip.run_cell("a")
427 437
428 438 nt.assert_equal(monitor, [])
429 439 _ip.magic("reset -f")
430 440 nt.assert_equal(monitor, [1])
431 441
432 442 class TestXdel(tt.TempFileMixin):
433 443 def test_xdel(self):
434 444 """Test that references from %run are cleared by xdel."""
435 445 src = ("class A(object):\n"
436 446 " monitor = []\n"
437 447 " def __del__(self):\n"
438 448 " self.monitor.append(1)\n"
439 449 "a = A()\n")
440 450 self.mktmp(src)
441 451 # %run creates some hidden references...
442 452 _ip.magic("run %s" % self.fname)
443 453 # ... as does the displayhook.
444 454 _ip.run_cell("a")
445 455
446 456 monitor = _ip.user_ns["A"].monitor
447 457 nt.assert_equal(monitor, [])
448 458
449 459 _ip.magic("xdel a")
450 460
451 461 # Check that a's __del__ method has been called.
452 462 nt.assert_equal(monitor, [1])
453 463
454 464 def doctest_who():
455 465 """doctest for %who
456 466
457 467 In [1]: %reset -f
458 468
459 469 In [2]: alpha = 123
460 470
461 471 In [3]: beta = 'beta'
462 472
463 473 In [4]: %who int
464 474 alpha
465 475
466 476 In [5]: %who str
467 477 beta
468 478
469 479 In [6]: %whos
470 480 Variable Type Data/Info
471 481 ----------------------------
472 482 alpha int 123
473 483 beta str beta
474 484
475 485 In [7]: %who_ls
476 486 Out[7]: ['alpha', 'beta']
477 487 """
478 488
479 489 def test_whos():
480 490 """Check that whos is protected against objects where repr() fails."""
481 491 class A(object):
482 492 def __repr__(self):
483 493 raise Exception()
484 494 _ip.user_ns['a'] = A()
485 495 _ip.magic("whos")
486 496
487 497 @py3compat.u_format
488 498 def doctest_precision():
489 499 """doctest for %precision
490 500
491 501 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
492 502
493 503 In [2]: %precision 5
494 504 Out[2]: {u}'%.5f'
495 505
496 506 In [3]: f.float_format
497 507 Out[3]: {u}'%.5f'
498 508
499 509 In [4]: %precision %e
500 510 Out[4]: {u}'%e'
501 511
502 512 In [5]: f(3.1415927)
503 513 Out[5]: {u}'3.141593e+00'
504 514 """
505 515
506 516 def test_psearch():
507 517 with tt.AssertPrints("dict.fromkeys"):
508 518 _ip.run_cell("dict.fr*?")
509 519
510 520 def test_timeit_shlex():
511 521 """test shlex issues with timeit (#1109)"""
512 522 _ip.ex("def f(*a,**kw): pass")
513 523 _ip.magic('timeit -n1 "this is a bug".count(" ")')
514 524 _ip.magic('timeit -r1 -n1 f(" ", 1)')
515 525 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
516 526 _ip.magic('timeit -r1 -n1 ("a " + "b")')
517 527 _ip.magic('timeit -r1 -n1 f("a " + "b")')
518 528 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
519 529
520 530
521 531 def test_timeit_arguments():
522 532 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
523 533 _ip.magic("timeit ('#')")
524 534
525 535
526 536 def test_timeit_special_syntax():
527 537 "Test %%timeit with IPython special syntax"
528 538 @register_line_magic
529 539 def lmagic(line):
530 540 ip = get_ipython()
531 541 ip.user_ns['lmagic_out'] = line
532 542
533 543 # line mode test
534 544 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
535 545 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
536 546 # cell mode test
537 547 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
538 548 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
539 549
540 550 def test_timeit_return():
541 551 """
542 552 test wether timeit -o return object
543 553 """
544 554
545 555 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
546 556 assert(res is not None)
547 557
548 558 def test_timeit_quiet():
549 559 """
550 560 test quiet option of timeit magic
551 561 """
552 562 with tt.AssertNotPrints("loops"):
553 563 _ip.run_cell("%timeit -n1 -r1 -q 1")
554 564
555 565 @dec.skipif(execution.profile is None)
556 566 def test_prun_special_syntax():
557 567 "Test %%prun with IPython special syntax"
558 568 @register_line_magic
559 569 def lmagic(line):
560 570 ip = get_ipython()
561 571 ip.user_ns['lmagic_out'] = line
562 572
563 573 # line mode test
564 574 _ip.run_line_magic('prun', '-q %lmagic my line')
565 575 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
566 576 # cell mode test
567 577 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
568 578 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
569 579
570 580 @dec.skipif(execution.profile is None)
571 581 def test_prun_quotes():
572 582 "Test that prun does not clobber string escapes (GH #1302)"
573 583 _ip.magic(r"prun -q x = '\t'")
574 584 nt.assert_equal(_ip.user_ns['x'], '\t')
575 585
576 586 def test_extension():
577 587 tmpdir = TemporaryDirectory()
578 588 orig_ipython_dir = _ip.ipython_dir
579 589 try:
580 590 _ip.ipython_dir = tmpdir.name
581 591 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
582 592 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
583 593 _ip.magic("install_ext %s" % url)
584 594 _ip.user_ns.pop('arq', None)
585 595 invalidate_caches() # Clear import caches
586 596 _ip.magic("load_ext daft_extension")
587 597 nt.assert_equal(_ip.user_ns['arq'], 185)
588 598 _ip.magic("unload_ext daft_extension")
589 599 assert 'arq' not in _ip.user_ns
590 600 finally:
591 601 _ip.ipython_dir = orig_ipython_dir
592 602 tmpdir.cleanup()
593 603
594 604 def test_notebook_export_json():
595 605 with TemporaryDirectory() as td:
596 606 outfile = os.path.join(td, "nb.ipynb")
597 607 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
598 608 _ip.magic("notebook -e %s" % outfile)
599 609
600 610 def test_notebook_export_py():
601 611 with TemporaryDirectory() as td:
602 612 outfile = os.path.join(td, "nb.py")
603 613 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
604 614 _ip.magic("notebook -e %s" % outfile)
605 615
606 616 def test_notebook_reformat_py():
607 617 with TemporaryDirectory() as td:
608 618 infile = os.path.join(td, "nb.ipynb")
609 619 with io.open(infile, 'w', encoding='utf-8') as f:
610 620 current.write(nb0, f, 'json')
611 621
612 622 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
613 623 _ip.magic("notebook -f py %s" % infile)
614 624
615 625 def test_notebook_reformat_json():
616 626 with TemporaryDirectory() as td:
617 627 infile = os.path.join(td, "nb.py")
618 628 with io.open(infile, 'w', encoding='utf-8') as f:
619 629 current.write(nb0, f, 'py')
620 630
621 631 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
622 632 _ip.magic("notebook -f ipynb %s" % infile)
623 633 _ip.magic("notebook -f json %s" % infile)
624 634
625 635 def test_env():
626 636 env = _ip.magic("env")
627 637 assert isinstance(env, dict), type(env)
628 638
629 639
630 640 class CellMagicTestCase(TestCase):
631 641
632 642 def check_ident(self, magic):
633 643 # Manually called, we get the result
634 644 out = _ip.run_cell_magic(magic, 'a', 'b')
635 645 nt.assert_equal(out, ('a','b'))
636 646 # Via run_cell, it goes into the user's namespace via displayhook
637 647 _ip.run_cell('%%' + magic +' c\nd')
638 648 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
639 649
640 650 def test_cell_magic_func_deco(self):
641 651 "Cell magic using simple decorator"
642 652 @register_cell_magic
643 653 def cellm(line, cell):
644 654 return line, cell
645 655
646 656 self.check_ident('cellm')
647 657
648 658 def test_cell_magic_reg(self):
649 659 "Cell magic manually registered"
650 660 def cellm(line, cell):
651 661 return line, cell
652 662
653 663 _ip.register_magic_function(cellm, 'cell', 'cellm2')
654 664 self.check_ident('cellm2')
655 665
656 666 def test_cell_magic_class(self):
657 667 "Cell magics declared via a class"
658 668 @magics_class
659 669 class MyMagics(Magics):
660 670
661 671 @cell_magic
662 672 def cellm3(self, line, cell):
663 673 return line, cell
664 674
665 675 _ip.register_magics(MyMagics)
666 676 self.check_ident('cellm3')
667 677
668 678 def test_cell_magic_class2(self):
669 679 "Cell magics declared via a class, #2"
670 680 @magics_class
671 681 class MyMagics2(Magics):
672 682
673 683 @cell_magic('cellm4')
674 684 def cellm33(self, line, cell):
675 685 return line, cell
676 686
677 687 _ip.register_magics(MyMagics2)
678 688 self.check_ident('cellm4')
679 689 # Check that nothing is registered as 'cellm33'
680 690 c33 = _ip.find_cell_magic('cellm33')
681 691 nt.assert_equal(c33, None)
682 692
683 693 def test_file():
684 694 """Basic %%file"""
685 695 ip = get_ipython()
686 696 with TemporaryDirectory() as td:
687 697 fname = os.path.join(td, 'file1')
688 698 ip.run_cell_magic("file", fname, u'\n'.join([
689 699 'line1',
690 700 'line2',
691 701 ]))
692 702 with open(fname) as f:
693 703 s = f.read()
694 704 nt.assert_in('line1\n', s)
695 705 nt.assert_in('line2', s)
696 706
697 707 def test_file_var_expand():
698 708 """%%file $filename"""
699 709 ip = get_ipython()
700 710 with TemporaryDirectory() as td:
701 711 fname = os.path.join(td, 'file1')
702 712 ip.user_ns['filename'] = fname
703 713 ip.run_cell_magic("file", '$filename', u'\n'.join([
704 714 'line1',
705 715 'line2',
706 716 ]))
707 717 with open(fname) as f:
708 718 s = f.read()
709 719 nt.assert_in('line1\n', s)
710 720 nt.assert_in('line2', s)
711 721
712 722 def test_file_unicode():
713 723 """%%file with unicode cell"""
714 724 ip = get_ipython()
715 725 with TemporaryDirectory() as td:
716 726 fname = os.path.join(td, 'file1')
717 727 ip.run_cell_magic("file", fname, u'\n'.join([
718 728 u'linΓ©1',
719 729 u'linΓ©2',
720 730 ]))
721 731 with io.open(fname, encoding='utf-8') as f:
722 732 s = f.read()
723 733 nt.assert_in(u'linΓ©1\n', s)
724 734 nt.assert_in(u'linΓ©2', s)
725 735
726 736 def test_file_amend():
727 737 """%%file -a amends files"""
728 738 ip = get_ipython()
729 739 with TemporaryDirectory() as td:
730 740 fname = os.path.join(td, 'file2')
731 741 ip.run_cell_magic("file", fname, u'\n'.join([
732 742 'line1',
733 743 'line2',
734 744 ]))
735 745 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
736 746 'line3',
737 747 'line4',
738 748 ]))
739 749 with open(fname) as f:
740 750 s = f.read()
741 751 nt.assert_in('line1\n', s)
742 752 nt.assert_in('line3\n', s)
743 753
744 754
745 755 def test_script_config():
746 756 ip = get_ipython()
747 757 ip.config.ScriptMagics.script_magics = ['whoda']
748 758 sm = script.ScriptMagics(shell=ip)
749 759 nt.assert_in('whoda', sm.magics['cell'])
750 760
751 761 @dec.skip_win32
752 762 def test_script_out():
753 763 ip = get_ipython()
754 764 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
755 765 nt.assert_equal(ip.user_ns['output'], 'hi\n')
756 766
757 767 @dec.skip_win32
758 768 def test_script_err():
759 769 ip = get_ipython()
760 770 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
761 771 nt.assert_equal(ip.user_ns['error'], 'hello\n')
762 772
763 773 @dec.skip_win32
764 774 def test_script_out_err():
765 775 ip = get_ipython()
766 776 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
767 777 nt.assert_equal(ip.user_ns['output'], 'hi\n')
768 778 nt.assert_equal(ip.user_ns['error'], 'hello\n')
769 779
770 780 @dec.skip_win32
771 781 def test_script_bg_out():
772 782 ip = get_ipython()
773 783 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
774 784 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
775 785
776 786 @dec.skip_win32
777 787 def test_script_bg_err():
778 788 ip = get_ipython()
779 789 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
780 790 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
781 791
782 792 @dec.skip_win32
783 793 def test_script_bg_out_err():
784 794 ip = get_ipython()
785 795 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
786 796 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
787 797 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
788 798
789 799 def test_script_defaults():
790 800 ip = get_ipython()
791 801 for cmd in ['sh', 'bash', 'perl', 'ruby']:
792 802 try:
793 803 find_cmd(cmd)
794 804 except Exception:
795 805 pass
796 806 else:
797 807 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
798 808
799 809
800 810 @magics_class
801 811 class FooFoo(Magics):
802 812 """class with both %foo and %%foo magics"""
803 813 @line_magic('foo')
804 814 def line_foo(self, line):
805 815 "I am line foo"
806 816 pass
807 817
808 818 @cell_magic("foo")
809 819 def cell_foo(self, line, cell):
810 820 "I am cell foo, not line foo"
811 821 pass
812 822
813 823 def test_line_cell_info():
814 824 """%%foo and %foo magics are distinguishable to inspect"""
815 825 ip = get_ipython()
816 826 ip.magics_manager.register(FooFoo)
817 827 oinfo = ip.object_inspect('foo')
818 828 nt.assert_true(oinfo['found'])
819 829 nt.assert_true(oinfo['ismagic'])
820 830
821 831 oinfo = ip.object_inspect('%%foo')
822 832 nt.assert_true(oinfo['found'])
823 833 nt.assert_true(oinfo['ismagic'])
824 834 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
825 835
826 836 oinfo = ip.object_inspect('%foo')
827 837 nt.assert_true(oinfo['found'])
828 838 nt.assert_true(oinfo['ismagic'])
829 839 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
830 840
831 841 def test_multiple_magics():
832 842 ip = get_ipython()
833 843 foo1 = FooFoo(ip)
834 844 foo2 = FooFoo(ip)
835 845 mm = ip.magics_manager
836 846 mm.register(foo1)
837 847 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
838 848 mm.register(foo2)
839 849 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
840 850
841 851 def test_alias_magic():
842 852 """Test %alias_magic."""
843 853 ip = get_ipython()
844 854 mm = ip.magics_manager
845 855
846 856 # Basic operation: both cell and line magics are created, if possible.
847 857 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
848 858 nt.assert_in('timeit_alias', mm.magics['line'])
849 859 nt.assert_in('timeit_alias', mm.magics['cell'])
850 860
851 861 # --cell is specified, line magic not created.
852 862 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
853 863 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
854 864 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
855 865
856 866 # Test that line alias is created successfully.
857 867 ip.run_line_magic('alias_magic', '--line env_alias env')
858 868 nt.assert_equal(ip.run_line_magic('env', ''),
859 869 ip.run_line_magic('env_alias', ''))
860 870
861 871 def test_save():
862 872 """Test %save."""
863 873 ip = get_ipython()
864 874 ip.history_manager.reset() # Clear any existing history.
865 875 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
866 876 for i, cmd in enumerate(cmds, start=1):
867 877 ip.history_manager.store_inputs(i, cmd)
868 878 with TemporaryDirectory() as tmpdir:
869 879 file = os.path.join(tmpdir, "testsave.py")
870 880 ip.run_line_magic("save", "%s 1-10" % file)
871 881 with open(file) as f:
872 882 content = f.read()
873 883 nt.assert_equal(content.count(cmds[0]), 1)
874 884 nt.assert_in('coding: utf-8', content)
875 885 ip.run_line_magic("save", "-a %s 1-10" % file)
876 886 with open(file) as f:
877 887 content = f.read()
878 888 nt.assert_equal(content.count(cmds[0]), 2)
879 889 nt.assert_in('coding: utf-8', content)
880 890
881 891
882 892 def test_store():
883 893 """Test %store."""
884 894 ip = get_ipython()
885 895 ip.run_line_magic('load_ext', 'storemagic')
886 896
887 897 # make sure the storage is empty
888 898 ip.run_line_magic('store', '-z')
889 899 ip.user_ns['var'] = 42
890 900 ip.run_line_magic('store', 'var')
891 901 ip.user_ns['var'] = 39
892 902 ip.run_line_magic('store', '-r')
893 903 nt.assert_equal(ip.user_ns['var'], 42)
894 904
895 905 ip.run_line_magic('store', '-d var')
896 906 ip.user_ns['var'] = 39
897 907 ip.run_line_magic('store' , '-r')
898 908 nt.assert_equal(ip.user_ns['var'], 39)
899 909
900 910
901 911 def _run_edit_test(arg_s, exp_filename=None,
902 912 exp_lineno=-1,
903 913 exp_contents=None,
904 914 exp_is_temp=None):
905 915 ip = get_ipython()
906 916 M = code.CodeMagics(ip)
907 917 last_call = ['','']
908 918 opts,args = M.parse_options(arg_s,'prxn:')
909 919 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
910 920
911 921 if exp_filename is not None:
912 922 nt.assert_equal(exp_filename, filename)
913 923 if exp_contents is not None:
914 924 with io.open(filename, 'r', encoding='utf-8') as f:
915 925 contents = f.read()
916 926 nt.assert_equal(exp_contents, contents)
917 927 if exp_lineno != -1:
918 928 nt.assert_equal(exp_lineno, lineno)
919 929 if exp_is_temp is not None:
920 930 nt.assert_equal(exp_is_temp, is_temp)
921 931
922 932
923 933 def test_edit_interactive():
924 934 """%edit on interactively defined objects"""
925 935 ip = get_ipython()
926 936 n = ip.execution_count
927 937 ip.run_cell(u"def foo(): return 1", store_history=True)
928 938
929 939 try:
930 940 _run_edit_test("foo")
931 941 except code.InteractivelyDefined as e:
932 942 nt.assert_equal(e.index, n)
933 943 else:
934 944 raise AssertionError("Should have raised InteractivelyDefined")
935 945
936 946
937 947 def test_edit_cell():
938 948 """%edit [cell id]"""
939 949 ip = get_ipython()
940 950
941 951 ip.run_cell(u"def foo(): return 1", store_history=True)
942 952
943 953 # test
944 954 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
945 955
946 956 def test_bookmark():
947 957 ip = get_ipython()
948 958 ip.run_line_magic('bookmark', 'bmname')
949 959 with tt.AssertPrints('bmname'):
950 960 ip.run_line_magic('bookmark', '-l')
951 961 ip.run_line_magic('bookmark', '-d bmname')
General Comments 0
You need to be logged in to leave comments. Login now