Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/IPython/core/magics/history.py: 20%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

153 statements  

1"""Implementation of magic functions related to History. 

2""" 

3#----------------------------------------------------------------------------- 

4# Copyright (c) 2012, IPython Development Team. 

5# 

6# Distributed under the terms of the Modified BSD License. 

7# 

8# The full license is in the file COPYING.txt, distributed with this software. 

9#----------------------------------------------------------------------------- 

10 

11#----------------------------------------------------------------------------- 

12# Imports 

13#----------------------------------------------------------------------------- 

14 

15# Stdlib 

16import os 

17import sys 

18from io import open as io_open 

19import fnmatch 

20 

21# Our own packages 

22from IPython.core.error import StdinNotImplementedError 

23from IPython.core.magic import Magics, magics_class, line_magic 

24from IPython.core.magic_arguments import (argument, magic_arguments, 

25 parse_argstring) 

26from IPython.testing.skipdoctest import skip_doctest 

27from IPython.utils import io 

28 

29#----------------------------------------------------------------------------- 

30# Magics class implementation 

31#----------------------------------------------------------------------------- 

32 

33 

34_unspecified = object() 

35 

36 

37@magics_class 

38class HistoryMagics(Magics): 

39 

40 @magic_arguments() 

41 @argument( 

42 '-n', dest='print_nums', action='store_true', default=False, 

43 help=""" 

44 print line numbers for each input. 

45 This feature is only available if numbered prompts are in use. 

46 """) 

47 @argument( 

48 '-o', dest='get_output', action='store_true', default=False, 

49 help="also print outputs for each input.") 

50 @argument( 

51 '-p', dest='pyprompts', action='store_true', default=False, 

52 help=""" 

53 print classic '>>>' python prompts before each input. 

54 This is useful for making documentation, and in conjunction 

55 with -o, for producing doctest-ready output. 

56 """) 

57 @argument( 

58 '-t', dest='raw', action='store_false', default=True, 

59 help=""" 

60 print the 'translated' history, as IPython understands it. 

61 IPython filters your input and converts it all into valid Python 

62 source before executing it (things like magics or aliases are turned 

63 into function calls, for example). With this option, you'll see the 

64 native history instead of the user-entered version: '%%cd /' will be 

65 seen as 'get_ipython().run_line_magic("cd", "/")' instead of '%%cd /'. 

66 """) 

67 @argument( 

68 '-f', dest='filename', 

69 help=""" 

70 FILENAME: instead of printing the output to the screen, redirect 

71 it to the given file. The file is always overwritten, though *when 

72 it can*, IPython asks for confirmation first. In particular, running 

73 the command 'history -f FILENAME' from the IPython Notebook 

74 interface will replace FILENAME even if it already exists *without* 

75 confirmation. 

76 """, 

77 ) 

78 @argument( 

79 "-y", 

80 dest="overwrite", 

81 help="yes, overwrite filename even if exists", 

82 action="store_true", 

83 default=None, 

84 ) 

85 @argument( 

86 "-g", 

87 dest="pattern", 

88 nargs="*", 

89 default=None, 

90 help=""" 

91 treat the arg as a glob pattern to search for in (full) history. 

92 This includes the saved history (almost all commands ever written). 

93 The pattern may contain '?' to match one unknown character and '*' 

94 to match any number of unknown characters. Use '%%hist -g' to show 

95 full saved history (may be very long). 

96 """) 

97 @argument( 

98 '-l', dest='limit', type=int, nargs='?', default=_unspecified, 

99 help=""" 

100 get the last n lines from all sessions. Specify n as a single 

101 arg, or the default is the last 10 lines. 

102 """) 

103 @argument( 

104 '-u', dest='unique', action='store_true', 

105 help=""" 

106 when searching history using `-g`, show only unique history. 

107 """) 

108 @argument('range', nargs='*') 

109 @skip_doctest 

110 @line_magic 

111 def history(self, parameter_s = ''): 

112 """Print input history (_i<n> variables), with most recent last. 

113 

114 By default, input history is printed without line numbers so it can be 

115 directly pasted into an editor. Use -n to show them. 

116 

117 By default, all input history from the current session is displayed. 

118 Ranges of history can be indicated using the syntax: 

119 

120 ``4`` 

121 Line 4, current session 

122 ``4-6`` 

123 Lines 4-6, current session 

124 ``243/1-5`` 

125 Lines 1-5, session 243 

126 ``~2/7`` 

127 Line 7, session 2 before current 

128 ``~8/1-~6/5`` 

129 From the first line of 8 sessions ago, to the fifth line of 6 

130 sessions ago. 

131 

132 Multiple ranges can be entered, separated by spaces 

133 

134 The same syntax is used by %macro, %save, %edit, %rerun 

135 

136 Examples 

137 -------- 

138 :: 

139 

140 In [6]: %history -n 4-6 

141 4:a = 12 

142 5:print(a**2) 

143 6:%history -n 4-6 

144 

145 """ 

146 

147 args = parse_argstring(self.history, parameter_s) 

148 

149 # For brevity 

150 history_manager = self.shell.history_manager 

151 

152 def _format_lineno(session, line): 

153 """Helper function to format line numbers properly.""" 

154 if session in (0, history_manager.session_number): 

155 return str(line) 

156 return "%s/%s" % (session, line) 

157 

158 # Check if output to specific file was requested. 

159 outfname = args.filename 

160 if not outfname: 

161 outfile = sys.stdout # default 

162 # We don't want to close stdout at the end! 

163 close_at_end = False 

164 else: 

165 outfname = os.path.expanduser(outfname) 

166 if args.overwrite is True: 

167 ans = True 

168 elif os.path.exists(outfname): 

169 ans = True 

170 if sys.stdin.isatty(): 

171 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname) 

172 else: 

173 try: 

174 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname) 

175 except StdinNotImplementedError: 

176 ans = True 

177 if not ans: 

178 print("Aborting.") 

179 return 

180 print("Overwriting file.") 

181 outfile = io_open(outfname, 'w', encoding='utf-8') 

182 close_at_end = True 

183 

184 print_nums = args.print_nums 

185 get_output = args.get_output 

186 pyprompts = args.pyprompts 

187 raw = args.raw 

188 

189 pattern = None 

190 limit = None if args.limit is _unspecified else args.limit 

191 

192 range_pattern = False 

193 if args.pattern is not None and not args.range: 

194 if args.pattern: 

195 pattern = "*" + " ".join(args.pattern) + "*" 

196 else: 

197 pattern = "*" 

198 hist = history_manager.search(pattern, raw=raw, output=get_output, 

199 n=limit, unique=args.unique) 

200 print_nums = True 

201 elif args.limit is not _unspecified: 

202 n = 10 if limit is None else limit 

203 hist = history_manager.get_tail(n, raw=raw, output=get_output) 

204 else: 

205 if args.pattern: 

206 range_pattern = "*" + " ".join(args.pattern) + "*" 

207 print_nums = True 

208 hist = history_manager.get_range_by_str( 

209 " ".join(args.range), raw, get_output 

210 ) 

211 

212 # We could be displaying the entire history, so let's not try to pull 

213 # it into a list in memory. Anything that needs more space will just 

214 # misalign. 

215 width = 4 

216 

217 for session, lineno, inline in hist: 

218 # Print user history with tabs expanded to 4 spaces. The GUI 

219 # clients use hard tabs for easier usability in auto-indented code, 

220 # but we want to produce PEP-8 compliant history for safe pasting 

221 # into an editor. 

222 if get_output: 

223 inline, output = inline 

224 if range_pattern: 

225 if not fnmatch.fnmatch(inline, range_pattern): 

226 continue 

227 inline = inline.expandtabs(4).rstrip() 

228 

229 multiline = "\n" in inline 

230 line_sep = '\n' if multiline else ' ' 

231 if print_nums: 

232 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width), 

233 line_sep), file=outfile, end=u'') 

234 if pyprompts: 

235 print(u">>> ", end=u"", file=outfile) 

236 if multiline: 

237 inline = "\n... ".join(inline.splitlines()) + "\n..." 

238 print(inline, file=outfile) 

239 if get_output and output: 

240 print(output, file=outfile) 

241 

242 if close_at_end: 

243 outfile.close() 

244 

245 @line_magic 

246 def recall(self, arg): 

247 r"""Repeat a command, or get command to input line for editing. 

248 

249 %recall and %rep are equivalent. 

250 

251 - %recall (no arguments): 

252 

253 Place a string version of last computation result (stored in the 

254 special '_' variable) to the next input prompt. Allows you to create 

255 elaborate command lines without using copy-paste:: 

256 

257 In[1]: l = ["hei", "vaan"] 

258 In[2]: "".join(l) 

259 Out[2]: heivaan 

260 In[3]: %recall 

261 In[4]: heivaan_ <== cursor blinking 

262 

263 %recall 45 

264 

265 Place history line 45 on the next input prompt. Use %hist to find 

266 out the number. 

267 

268 %recall 1-4 

269 

270 Combine the specified lines into one cell, and place it on the next 

271 input prompt. See %history for the slice syntax. 

272 

273 %recall foo+bar 

274 

275 If foo+bar can be evaluated in the user namespace, the result is 

276 placed at the next input prompt. Otherwise, the history is searched 

277 for lines which contain that substring, and the most recent one is 

278 placed at the next input prompt. 

279 """ 

280 if not arg: # Last output 

281 self.shell.set_next_input(str(self.shell.user_ns["_"])) 

282 return 

283 # Get history range 

284 histlines = self.shell.history_manager.get_range_by_str(arg) 

285 cmd = "\n".join(x[2] for x in histlines) 

286 if cmd: 

287 self.shell.set_next_input(cmd.rstrip()) 

288 return 

289 

290 try: # Variable in user namespace 

291 cmd = str(eval(arg, self.shell.user_ns)) 

292 except Exception: # Search for term in history 

293 histlines = self.shell.history_manager.search("*"+arg+"*") 

294 for h in reversed([x[2] for x in histlines]): 

295 if 'recall' in h or 'rep' in h: 

296 continue 

297 self.shell.set_next_input(h.rstrip()) 

298 return 

299 else: 

300 self.shell.set_next_input(cmd.rstrip()) 

301 return 

302 print("Couldn't evaluate or find in history:", arg) 

303 

304 @line_magic 

305 def rerun(self, parameter_s=''): 

306 """Re-run previous input 

307 

308 By default, you can specify ranges of input history to be repeated 

309 (as with %history). With no arguments, it will repeat the last line. 

310 

311 Options: 

312 

313 -l <n> : Repeat the last n lines of input, not including the 

314 current command. 

315 

316 -g foo : Repeat the most recent line which contains foo 

317 """ 

318 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string') 

319 if "l" in opts: # Last n lines 

320 try: 

321 n = int(opts["l"]) 

322 except ValueError: 

323 print("Number of lines must be an integer") 

324 return 

325 

326 if n == 0: 

327 print("Requested 0 last lines - nothing to run") 

328 return 

329 elif n < 0: 

330 print("Number of lines to rerun cannot be negative") 

331 return 

332 

333 hist = self.shell.history_manager.get_tail(n) 

334 elif "g" in opts: # Search 

335 p = "*"+opts['g']+"*" 

336 hist = list(self.shell.history_manager.search(p)) 

337 for l in reversed(hist): 

338 if "rerun" not in l[2]: 

339 hist = [l] # The last match which isn't a %rerun 

340 break 

341 else: 

342 hist = [] # No matches except %rerun 

343 elif args: # Specify history ranges 

344 hist = self.shell.history_manager.get_range_by_str(args) 

345 else: # Last line 

346 hist = self.shell.history_manager.get_tail(1) 

347 hist = [x[2] for x in hist] 

348 if not hist: 

349 print("No lines in history match specification") 

350 return 

351 histlines = "\n".join(hist) 

352 print("=== Executing: ===") 

353 print(histlines) 

354 print("=== Output: ===") 

355 self.shell.run_cell("\n".join(hist), store_history=False)