##// END OF EJS Templates
Refactor code-finding logic, and use it for %save and %macro as well.
Thomas Kluyver -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,748 +1,748 b''
1 1 """ History related magics and functionality """
2 2 #-----------------------------------------------------------------------------
3 3 # Copyright (C) 2010 The IPython Development Team.
4 4 #
5 5 # Distributed under the terms of the BSD License.
6 6 #
7 7 # The full license is in the file COPYING.txt, distributed with this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13 from __future__ import print_function
14 14
15 15 # Stdlib imports
16 16 import datetime
17 17 import json
18 18 import os
19 19 import re
20 20 import sqlite3
21 21
22 22 from collections import defaultdict
23 23
24 24 # Our own packages
25 25 from IPython.config.configurable import Configurable
26 26 import IPython.utils.io
27 27
28 28 from IPython.testing import decorators as testdec
29 29 from IPython.utils.io import ask_yes_no
30 30 from IPython.utils.traitlets import Bool, Dict, Instance, Int, List, Unicode
31 31 from IPython.utils.warn import warn
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Classes and functions
35 35 #-----------------------------------------------------------------------------
36 36
37 37 class HistoryManager(Configurable):
38 38 """A class to organize all history-related functionality in one place.
39 39 """
40 40 # Public interface
41 41
42 42 # An instance of the IPython shell we are attached to
43 43 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
44 44 # Lists to hold processed and raw history. These start with a blank entry
45 45 # so that we can index them starting from 1
46 46 input_hist_parsed = List([""])
47 47 input_hist_raw = List([""])
48 48 # A list of directories visited during session
49 49 dir_hist = List()
50 50 def _dir_hist_default(self):
51 51 try:
52 52 return [os.getcwd()]
53 53 except OSError:
54 54 return []
55 55
56 56 # A dict of output history, keyed with ints from the shell's
57 57 # execution count. If there are several outputs from one command,
58 58 # only the last one is stored.
59 59 output_hist = Dict()
60 60 # Contains all outputs, in lists of reprs.
61 61 output_hist_reprs = Instance(defaultdict, args=(list,))
62 62
63 63 # String holding the path to the history file
64 64 hist_file = Unicode(config=True)
65 65
66 66 # The SQLite database
67 67 db = Instance(sqlite3.Connection)
68 68 # The number of the current session in the history database
69 69 session_number = Int()
70 70 # Should we log output to the database? (default no)
71 71 db_log_output = Bool(False, config=True)
72 72 # Write to database every x commands (higher values save disk access & power)
73 73 # Values of 1 or less effectively disable caching.
74 74 db_cache_size = Int(0, config=True)
75 75 # The input and output caches
76 76 db_input_cache = List()
77 77 db_output_cache = List()
78 78
79 79 # Private interface
80 80 # Variables used to store the three last inputs from the user. On each new
81 81 # history update, we populate the user's namespace with these, shifted as
82 82 # necessary.
83 83 _i00 = Unicode(u'')
84 84 _i = Unicode(u'')
85 85 _ii = Unicode(u'')
86 86 _iii = Unicode(u'')
87 87
88 88 # A set with all forms of the exit command, so that we don't store them in
89 89 # the history (it's annoying to rewind the first entry and land on an exit
90 90 # call).
91 91 _exit_commands = Instance(set, args=(['Quit', 'quit', 'Exit', 'exit',
92 92 '%Quit', '%quit', '%Exit', '%exit'],))
93 93
94 94 def __init__(self, shell, config=None, **traits):
95 95 """Create a new history manager associated with a shell instance.
96 96 """
97 97 # We need a pointer back to the shell for various tasks.
98 98 super(HistoryManager, self).__init__(shell=shell, config=config,
99 99 **traits)
100 100
101 101 if self.hist_file == u'':
102 102 # No one has set the hist_file, yet.
103 103 if shell.profile:
104 104 histfname = 'history-%s' % shell.profile
105 105 else:
106 106 histfname = 'history'
107 107 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.sqlite')
108 108
109 109 try:
110 110 self.init_db()
111 111 except sqlite3.DatabaseError:
112 112 if os.path.isfile(self.hist_file):
113 113 # Try to move the file out of the way.
114 114 newpath = os.path.join(self.shell.ipython_dir, "hist-corrupt.sqlite")
115 115 os.rename(self.hist_file, newpath)
116 116 print("ERROR! History file wasn't a valid SQLite database.",
117 117 "It was moved to %s" % newpath, "and a new file created.")
118 118 self.init_db()
119 119 else:
120 120 # The hist_file is probably :memory: or something else.
121 121 raise
122 122
123 123 self.new_session()
124 124
125 125
126 126 def init_db(self):
127 127 """Connect to the database, and create tables if necessary."""
128 128 self.db = sqlite3.connect(self.hist_file)
129 129 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
130 130 primary key autoincrement, start timestamp,
131 131 end timestamp, num_cmds integer, remark text)""")
132 132 self.db.execute("""CREATE TABLE IF NOT EXISTS history
133 133 (session integer, line integer, source text, source_raw text,
134 134 PRIMARY KEY (session, line))""")
135 135 # Output history is optional, but ensure the table's there so it can be
136 136 # enabled later.
137 137 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
138 138 (session integer, line integer, output text,
139 139 PRIMARY KEY (session, line))""")
140 140 self.db.commit()
141 141
142 142 def new_session(self):
143 143 """Get a new session number."""
144 144 with self.db:
145 145 cur = self.db.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
146 146 NULL, "") """, (datetime.datetime.now(),))
147 147 self.session_number = cur.lastrowid
148 148
149 149 def end_session(self):
150 150 """Close the database session, filling in the end time and line count."""
151 151 self.writeout_cache()
152 152 with self.db:
153 153 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
154 154 session==?""", (datetime.datetime.now(),
155 155 len(self.input_hist_parsed)-1, self.session_number))
156 156 self.session_number = 0
157 157
158 158 def name_session(self, name):
159 159 """Give the current session a name in the history database."""
160 160 with self.db:
161 161 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
162 162 (name, self.session_number))
163 163
164 164 def reset(self, new_session=True):
165 165 """Clear the session history, releasing all object references, and
166 166 optionally open a new session."""
167 167 if self.session_number:
168 168 self.end_session()
169 169 self.input_hist_parsed[:] = [""]
170 170 self.input_hist_raw[:] = [""]
171 171 self.output_hist.clear()
172 172 # The directory history can't be completely empty
173 173 self.dir_hist[:] = [os.getcwd()]
174 174
175 175 if new_session:
176 176 self.new_session()
177 177
178 178 ## -------------------------------
179 179 ## Methods for retrieving history:
180 180 ## -------------------------------
181 181 def _run_sql(self, sql, params, raw=True, output=False):
182 182 """Prepares and runs an SQL query for the history database.
183 183
184 184 Parameters
185 185 ----------
186 186 sql : str
187 187 Any filtering expressions to go after SELECT ... FROM ...
188 188 params : tuple
189 189 Parameters passed to the SQL query (to replace "?")
190 190 raw, output : bool
191 191 See :meth:`get_range`
192 192
193 193 Returns
194 194 -------
195 195 Tuples as :meth:`get_range`
196 196 """
197 197 toget = 'source_raw' if raw else 'source'
198 198 sqlfrom = "history"
199 199 if output:
200 200 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
201 201 toget = "history.%s, output_history.output" % toget
202 202 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
203 203 (toget, sqlfrom) + sql, params)
204 204 if output: # Regroup into 3-tuples, and parse JSON
205 205 loads = lambda out: json.loads(out) if out else None
206 206 return ((ses, lin, (inp, loads(out))) \
207 207 for ses, lin, inp, out in cur)
208 208 return cur
209 209
210 210
211 211 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
212 212 """Get the last n lines from the history database.
213 213
214 214 Parameters
215 215 ----------
216 216 n : int
217 217 The number of lines to get
218 218 raw, output : bool
219 219 See :meth:`get_range`
220 220 include_latest : bool
221 221 If False (default), n+1 lines are fetched, and the latest one
222 222 is discarded. This is intended to be used where the function
223 223 is called by a user command, which it should not return.
224 224
225 225 Returns
226 226 -------
227 227 Tuples as :meth:`get_range`
228 228 """
229 229 self.writeout_cache()
230 230 if not include_latest:
231 231 n += 1
232 232 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
233 233 (n,), raw=raw, output=output)
234 234 if not include_latest:
235 235 return reversed(list(cur)[1:])
236 236 return reversed(list(cur))
237 237
238 238 def search(self, pattern="*", raw=True, search_raw=True,
239 239 output=False):
240 240 """Search the database using unix glob-style matching (wildcards
241 241 * and ?).
242 242
243 243 Parameters
244 244 ----------
245 245 pattern : str
246 246 The wildcarded pattern to match when searching
247 247 search_raw : bool
248 248 If True, search the raw input, otherwise, the parsed input
249 249 raw, output : bool
250 250 See :meth:`get_range`
251 251
252 252 Returns
253 253 -------
254 254 Tuples as :meth:`get_range`
255 255 """
256 256 tosearch = "source_raw" if search_raw else "source"
257 257 if output:
258 258 tosearch = "history." + tosearch
259 259 self.writeout_cache()
260 260 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
261 261 raw=raw, output=output)
262 262
263 263 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
264 264 """Get input and output history from the current session. Called by
265 265 get_range, and takes similar parameters."""
266 266 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
267 267
268 268 n = len(input_hist)
269 269 if start < 0:
270 270 start += n
271 271 if not stop:
272 272 stop = n
273 273 elif stop < 0:
274 274 stop += n
275 275
276 276 for i in range(start, stop):
277 277 if output:
278 278 line = (input_hist[i], self.output_hist_reprs.get(i))
279 279 else:
280 280 line = input_hist[i]
281 281 yield (0, i, line)
282 282
283 283 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
284 284 """Retrieve input by session.
285 285
286 286 Parameters
287 287 ----------
288 288 session : int
289 289 Session number to retrieve. The current session is 0, and negative
290 290 numbers count back from current session, so -1 is previous session.
291 291 start : int
292 292 First line to retrieve.
293 293 stop : int
294 294 End of line range (excluded from output itself). If None, retrieve
295 295 to the end of the session.
296 296 raw : bool
297 297 If True, return untranslated input
298 298 output : bool
299 299 If True, attempt to include output. This will be 'real' Python
300 300 objects for the current session, or text reprs from previous
301 301 sessions if db_log_output was enabled at the time. Where no output
302 302 is found, None is used.
303 303
304 304 Returns
305 305 -------
306 306 An iterator over the desired lines. Each line is a 3-tuple, either
307 307 (session, line, input) if output is False, or
308 308 (session, line, (input, output)) if output is True.
309 309 """
310 310 if session == 0 or session==self.session_number: # Current session
311 311 return self._get_range_session(start, stop, raw, output)
312 312 if session < 0:
313 313 session += self.session_number
314 314
315 315 if stop:
316 316 lineclause = "line >= ? AND line < ?"
317 317 params = (session, start, stop)
318 318 else:
319 319 lineclause = "line>=?"
320 320 params = (session, start)
321 321
322 322 return self._run_sql("WHERE session==? AND %s""" % lineclause,
323 323 params, raw=raw, output=output)
324 324
325 325 def get_range_by_str(self, rangestr, raw=True, output=False):
326 326 """Get lines of history from a string of ranges, as used by magic
327 327 commands %hist, %save, %macro, etc.
328 328
329 329 Parameters
330 330 ----------
331 331 rangestr : str
332 332 A string specifying ranges, e.g. "5 ~2/1-4". See
333 333 :func:`magic_history` for full details.
334 334 raw, output : bool
335 335 As :meth:`get_range`
336 336
337 337 Returns
338 338 -------
339 339 Tuples as :meth:`get_range`
340 340 """
341 341 for sess, s, e in extract_hist_ranges(rangestr):
342 342 for line in self.get_range(sess, s, e, raw=raw, output=output):
343 343 yield line
344 344
345 345 ## ----------------------------
346 346 ## Methods for storing history:
347 347 ## ----------------------------
348 348 def store_inputs(self, line_num, source, source_raw=None):
349 349 """Store source and raw input in history and create input cache
350 350 variables _i*.
351 351
352 352 Parameters
353 353 ----------
354 354 line_num : int
355 355 The prompt number of this input.
356 356
357 357 source : str
358 358 Python input.
359 359
360 360 source_raw : str, optional
361 361 If given, this is the raw input without any IPython transformations
362 362 applied to it. If not given, ``source`` is used.
363 363 """
364 364 if source_raw is None:
365 365 source_raw = source
366 366 source = source.rstrip('\n')
367 367 source_raw = source_raw.rstrip('\n')
368 368
369 369 # do not store exit/quit commands
370 370 if source_raw.strip() in self._exit_commands:
371 371 return
372 372
373 373 self.input_hist_parsed.append(source)
374 374 self.input_hist_raw.append(source_raw)
375 375
376 376 self.db_input_cache.append((line_num, source, source_raw))
377 377 # Trigger to flush cache and write to DB.
378 378 if len(self.db_input_cache) >= self.db_cache_size:
379 379 self.writeout_cache()
380 380
381 381 # update the auto _i variables
382 382 self._iii = self._ii
383 383 self._ii = self._i
384 384 self._i = self._i00
385 385 self._i00 = source_raw
386 386
387 387 # hackish access to user namespace to create _i1,_i2... dynamically
388 388 new_i = '_i%s' % line_num
389 389 to_main = {'_i': self._i,
390 390 '_ii': self._ii,
391 391 '_iii': self._iii,
392 392 new_i : self._i00 }
393 393 self.shell.user_ns.update(to_main)
394 394
395 395 def store_output(self, line_num):
396 396 """If database output logging is enabled, this saves all the
397 397 outputs from the indicated prompt number to the database. It's
398 398 called by run_cell after code has been executed.
399 399
400 400 Parameters
401 401 ----------
402 402 line_num : int
403 403 The line number from which to save outputs
404 404 """
405 405 if (not self.db_log_output) or not self.output_hist_reprs[line_num]:
406 406 return
407 407 output = json.dumps(self.output_hist_reprs[line_num])
408 408
409 409 self.db_output_cache.append((line_num, output))
410 410 if self.db_cache_size <= 1:
411 411 self.writeout_cache()
412 412
413 413 def _writeout_input_cache(self):
414 414 for line in self.db_input_cache:
415 415 with self.db:
416 416 self.db.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
417 417 (self.session_number,)+line)
418 418
419 419 def _writeout_output_cache(self):
420 420 for line in self.db_output_cache:
421 421 with self.db:
422 422 self.db.execute("INSERT INTO output_history VALUES (?, ?, ?)",
423 423 (self.session_number,)+line)
424 424
425 425 def writeout_cache(self):
426 426 """Write any entries in the cache to the database."""
427 427 try:
428 428 self._writeout_input_cache()
429 429 except sqlite3.IntegrityError:
430 430 self.new_session()
431 431 print("ERROR! Session/line number was not unique in",
432 432 "database. History logging moved to new session",
433 433 self.session_number)
434 434 try: # Try writing to the new session. If this fails, don't recurse
435 435 self.writeout_cache()
436 436 except sqlite3.IntegrityError:
437 437 pass
438 438 finally:
439 439 self.db_input_cache = []
440 440
441 441 try:
442 442 self._writeout_output_cache()
443 443 except sqlite3.IntegrityError:
444 444 print("!! Session/line number for output was not unique",
445 445 "in database. Output will not be stored.")
446 446 finally:
447 447 self.db_output_cache = []
448 448
449 449
450 450 # To match, e.g. ~5/8-~2/3
451 451 range_re = re.compile(r"""
452 452 ((?P<startsess>~?\d+)/)?
453 453 (?P<start>\d+) # Only the start line num is compulsory
454 454 ((?P<sep>[\-:])
455 455 ((?P<endsess>~?\d+)/)?
456 456 (?P<end>\d+))?
457 """, re.VERBOSE)
457 $""", re.VERBOSE)
458 458
459 459 def extract_hist_ranges(ranges_str):
460 460 """Turn a string of history ranges into 3-tuples of (session, start, stop).
461 461
462 462 Examples
463 463 --------
464 464 list(extract_input_ranges("~8/5-~7/4 2"))
465 465 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
466 466 """
467 467 for range_str in ranges_str.split():
468 468 rmatch = range_re.match(range_str)
469 469 if not rmatch:
470 470 continue
471 471 start = int(rmatch.group("start"))
472 472 end = rmatch.group("end")
473 473 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
474 474 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
475 475 end += 1
476 476 startsess = rmatch.group("startsess") or "0"
477 477 endsess = rmatch.group("endsess") or startsess
478 478 startsess = int(startsess.replace("~","-"))
479 479 endsess = int(endsess.replace("~","-"))
480 480 assert endsess >= startsess
481 481
482 482 if endsess == startsess:
483 483 yield (startsess, start, end)
484 484 continue
485 485 # Multiple sessions in one range:
486 486 yield (startsess, start, None)
487 487 for sess in range(startsess+1, endsess):
488 488 yield (sess, 1, None)
489 489 yield (endsess, 1, end)
490 490
491 491 def _format_lineno(session, line):
492 492 """Helper function to format line numbers properly."""
493 493 if session == 0:
494 494 return str(line)
495 495 return "%s#%s" % (session, line)
496 496
497 497 @testdec.skip_doctest
498 498 def magic_history(self, parameter_s = ''):
499 499 """Print input history (_i<n> variables), with most recent last.
500 500
501 501 %history -> print at most 40 inputs (some may be multi-line)\\
502 502 %history n -> print at most n inputs\\
503 503 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
504 504
505 505 By default, input history is printed without line numbers so it can be
506 506 directly pasted into an editor. Use -n to show them.
507 507
508 508 Ranges of history can be indicated using the syntax:
509 509 4 : Line 4, current session
510 510 4-6 : Lines 4-6, current session
511 511 243/1-5: Lines 1-5, session 243
512 512 ~2/7 : Line 7, session 2 before current
513 513 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
514 514 of 6 sessions ago.
515 515 Multiple ranges can be entered, separated by spaces
516 516
517 517 The same syntax is used by %macro, %save, %edit, %rerun
518 518
519 519 Options:
520 520
521 521 -n: print line numbers for each input.
522 522 This feature is only available if numbered prompts are in use.
523 523
524 524 -o: also print outputs for each input.
525 525
526 526 -p: print classic '>>>' python prompts before each input. This is useful
527 527 for making documentation, and in conjunction with -o, for producing
528 528 doctest-ready output.
529 529
530 530 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
531 531
532 532 -t: print the 'translated' history, as IPython understands it. IPython
533 533 filters your input and converts it all into valid Python source before
534 534 executing it (things like magics or aliases are turned into function
535 535 calls, for example). With this option, you'll see the native history
536 536 instead of the user-entered version: '%cd /' will be seen as
537 537 'get_ipython().magic("%cd /")' instead of '%cd /'.
538 538
539 539 -g: treat the arg as a pattern to grep for in (full) history.
540 540 This includes the saved history (almost all commands ever written).
541 541 Use '%hist -g' to show full saved history (may be very long).
542 542
543 543 -l: get the last n lines from all sessions. Specify n as a single arg, or
544 544 the default is the last 10 lines.
545 545
546 546 -f FILENAME: instead of printing the output to the screen, redirect it to
547 547 the given file. The file is always overwritten, though IPython asks for
548 548 confirmation first if it already exists.
549 549
550 550 Examples
551 551 --------
552 552 ::
553 553
554 554 In [6]: %hist -n 4 6
555 555 4:a = 12
556 556 5:print a**2
557 557
558 558 """
559 559
560 560 if not self.shell.displayhook.do_full_cache:
561 561 print('This feature is only available if numbered prompts are in use.')
562 562 return
563 563 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
564 564
565 565 # For brevity
566 566 history_manager = self.shell.history_manager
567 567
568 568 def _format_lineno(session, line):
569 569 """Helper function to format line numbers properly."""
570 570 if session in (0, history_manager.session_number):
571 571 return str(line)
572 572 return "%s/%s" % (session, line)
573 573
574 574 # Check if output to specific file was requested.
575 575 try:
576 576 outfname = opts['f']
577 577 except KeyError:
578 578 outfile = IPython.utils.io.Term.cout # default
579 579 # We don't want to close stdout at the end!
580 580 close_at_end = False
581 581 else:
582 582 if os.path.exists(outfname):
583 583 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
584 584 print('Aborting.')
585 585 return
586 586
587 587 outfile = open(outfname,'w')
588 588 close_at_end = True
589 589
590 590 print_nums = 'n' in opts
591 591 get_output = 'o' in opts
592 592 pyprompts = 'p' in opts
593 593 # Raw history is the default
594 594 raw = not('t' in opts)
595 595
596 596 default_length = 40
597 597 pattern = None
598 598
599 599 if 'g' in opts: # Glob search
600 600 pattern = "*" + args + "*" if args else "*"
601 601 hist = history_manager.search(pattern, raw=raw, output=get_output)
602 602 elif 'l' in opts: # Get 'tail'
603 603 try:
604 604 n = int(args)
605 605 except ValueError, IndexError:
606 606 n = 10
607 607 hist = history_manager.get_tail(n, raw=raw, output=get_output)
608 608 else:
609 609 if args: # Get history by ranges
610 610 hist = history_manager.get_range_by_str(args, raw, get_output)
611 611 else: # Just get history for the current session
612 612 hist = history_manager.get_range(raw=raw, output=get_output)
613 613
614 614 # We could be displaying the entire history, so let's not try to pull it
615 615 # into a list in memory. Anything that needs more space will just misalign.
616 616 width = 4
617 617
618 618 for session, lineno, inline in hist:
619 619 # Print user history with tabs expanded to 4 spaces. The GUI clients
620 620 # use hard tabs for easier usability in auto-indented code, but we want
621 621 # to produce PEP-8 compliant history for safe pasting into an editor.
622 622 if get_output:
623 623 inline, output = inline
624 624 inline = inline.expandtabs(4).rstrip()
625 625
626 626 multiline = "\n" in inline
627 627 line_sep = '\n' if multiline else ' '
628 628 if print_nums:
629 629 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
630 630 line_sep), file=outfile, end='')
631 631 if pyprompts:
632 632 print(">>> ", end="", file=outfile)
633 633 if multiline:
634 634 inline = "\n... ".join(inline.splitlines()) + "\n..."
635 635 print(inline, file=outfile)
636 636 if get_output and output:
637 637 print("\n".join(output), file=outfile)
638 638
639 639 if close_at_end:
640 640 outfile.close()
641 641
642 642
643 643 def magic_rep(self, arg):
644 644 r""" Repeat a command, or get command to input line for editing
645 645
646 646 - %rep (no arguments):
647 647
648 648 Place a string version of last computation result (stored in the special '_'
649 649 variable) to the next input prompt. Allows you to create elaborate command
650 650 lines without using copy-paste::
651 651
652 652 In[1]: l = ["hei", "vaan"]
653 653 In[2]: "".join(l)
654 654 Out[2]: heivaan
655 655 In[3]: %rep
656 656 In[4]: heivaan_ <== cursor blinking
657 657
658 658 %rep 45
659 659
660 660 Place history line 45 on the next input prompt. Use %hist to find
661 661 out the number.
662 662
663 663 %rep 1-4
664 664
665 665 Combine the specified lines into one cell, and place it on the next
666 666 input prompt. See %history for the slice syntax.
667 667
668 668 %rep foo+bar
669 669
670 670 If foo+bar can be evaluated in the user namespace, the result is
671 671 placed at the next input prompt. Otherwise, the history is searched
672 672 for lines which contain that substring, and the most recent one is
673 673 placed at the next input prompt.
674 674 """
675 675 if not arg: # Last output
676 676 self.set_next_input(str(self.shell.user_ns["_"]))
677 677 return
678 678 # Get history range
679 679 histlines = self.history_manager.get_range_by_str(arg)
680 680 cmd = "\n".join(x[2] for x in histlines)
681 681 if cmd:
682 682 self.set_next_input(cmd.rstrip())
683 683 return
684 684
685 685 try: # Variable in user namespace
686 686 cmd = str(eval(arg, self.shell.user_ns))
687 687 except Exception: # Search for term in history
688 688 histlines = self.history_manager.search("*"+arg+"*")
689 689 for h in reversed([x[2] for x in histlines]):
690 690 if 'rep' in h:
691 691 continue
692 692 self.set_next_input(h.rstrip())
693 693 return
694 694 else:
695 695 self.set_next_input(cmd.rstrip())
696 696 print("Couldn't evaluate or find in history:", arg)
697 697
698 698 def magic_rerun(self, parameter_s=''):
699 699 """Re-run previous input
700 700
701 701 By default, you can specify ranges of input history to be repeated
702 702 (as with %history). With no arguments, it will repeat the last line.
703 703
704 704 Options:
705 705
706 706 -l <n> : Repeat the last n lines of input, not including the
707 707 current command.
708 708
709 709 -g foo : Repeat the most recent line which contains foo
710 710 """
711 711 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
712 712 if "l" in opts: # Last n lines
713 713 n = int(opts['l'])
714 714 hist = self.history_manager.get_tail(n)
715 715 elif "g" in opts: # Search
716 716 p = "*"+opts['g']+"*"
717 717 hist = list(self.history_manager.search(p))
718 718 for l in reversed(hist):
719 719 if "rerun" not in l[2]:
720 720 hist = [l] # The last match which isn't a %rerun
721 721 break
722 722 else:
723 723 hist = [] # No matches except %rerun
724 724 elif args: # Specify history ranges
725 725 hist = self.history_manager.get_range_by_str(args)
726 726 else: # Last line
727 727 hist = self.history_manager.get_tail(1)
728 728 hist = [x[2] for x in hist]
729 729 if not hist:
730 730 print("No lines in history match specification")
731 731 return
732 732 histlines = "\n".join(hist)
733 733 print("=== Executing: ===")
734 734 print(histlines)
735 735 print("=== Output: ===")
736 736 self.run_cell("\n".join(hist), store_history=False)
737 737
738 738
739 739 def init_ipython(ip):
740 740 ip.define_magic("rep", magic_rep)
741 741 ip.define_magic("recall", magic_rep)
742 742 ip.define_magic("rerun", magic_rerun)
743 743 ip.define_magic("hist",magic_history) # Alternative name
744 744 ip.define_magic("history",magic_history)
745 745
746 746 # XXX - ipy_completers are in quarantine, need to be updated to new apis
747 747 #import ipy_completers
748 748 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
@@ -1,33 +1,53 b''
1 1 """Support for interactive macros in IPython"""
2 2
3 3 #*****************************************************************************
4 4 # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
5 5 #
6 6 # Distributed under the terms of the BSD License. The full license is in
7 7 # the file COPYING, distributed as part of this software.
8 8 #*****************************************************************************
9 9
10 import re
11 import sys
12
10 13 import IPython.utils.io
11 14
15 coding_declaration = re.compile(r"#\s*coding[:=]\s*([-\w.]+)")
16
12 17 class Macro(object):
13 18 """Simple class to store the value of macros as strings.
14 19
15 20 Macro is just a callable that executes a string of IPython
16 21 input when called.
17 22
18 23 Args to macro are available in _margv list if you need them.
19 24 """
20 25
21 26 def __init__(self,code):
22 27 """store the macro value, as a single string which can be executed"""
23 self.value = code.rstrip()+'\n'
24
28 lines = []
29 enc = None
30 for line in code.splitlines():
31 coding_match = coding_declaration.match(line)
32 if coding_match:
33 enc = coding_match.group(1)
34 else:
35 lines.append(line)
36 code = "\n".join(lines)
37 if isinstance(code, bytes):
38 code = code.decode(enc or sys.getdefaultencoding())
39 self.value = code + '\n'
40
25 41 def __str__(self):
42 enc = sys.stdin.encoding or sys.getdefaultencoding()
43 return self.value.encode(enc, "replace")
44
45 def __unicode__(self):
26 46 return self.value
27 47
28 48 def __repr__(self):
29 49 return 'IPython.macro.Macro(%s)' % repr(self.value)
30 50
31 51 def __getstate__(self):
32 52 """ needed for safe pickling via %store """
33 53 return {'value': self.value}
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now