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

146 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

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 @argument( 

78 '-g', dest='pattern', nargs='*', default=None, 

79 help=""" 

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

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

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

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

84 full saved history (may be very long). 

85 """) 

86 @argument( 

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

88 help=""" 

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

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

91 """) 

92 @argument( 

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

94 help=""" 

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

96 """) 

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

98 @skip_doctest 

99 @line_magic 

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

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

102 

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

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

105 

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

107 Ranges of history can be indicated using the syntax: 

108 

109 ``4`` 

110 Line 4, current session 

111 ``4-6`` 

112 Lines 4-6, current session 

113 ``243/1-5`` 

114 Lines 1-5, session 243 

115 ``~2/7`` 

116 Line 7, session 2 before current 

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

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

119 sessions ago. 

120 

121 Multiple ranges can be entered, separated by spaces 

122 

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

124 

125 Examples 

126 -------- 

127 :: 

128 

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

130 4:a = 12 

131 5:print a**2 

132 6:%history -n 4-6 

133 

134 """ 

135 

136 args = parse_argstring(self.history, parameter_s) 

137 

138 # For brevity 

139 history_manager = self.shell.history_manager 

140 

141 def _format_lineno(session, line): 

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

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

144 return str(line) 

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

146 

147 # Check if output to specific file was requested. 

148 outfname = args.filename 

149 if not outfname: 

150 outfile = sys.stdout # default 

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

152 close_at_end = False 

153 else: 

154 outfname = os.path.expanduser(outfname) 

155 if os.path.exists(outfname): 

156 try: 

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

158 except StdinNotImplementedError: 

159 ans = True 

160 if not ans: 

161 print('Aborting.') 

162 return 

163 print("Overwriting file.") 

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

165 close_at_end = True 

166 

167 print_nums = args.print_nums 

168 get_output = args.get_output 

169 pyprompts = args.pyprompts 

170 raw = args.raw 

171 

172 pattern = None 

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

174 

175 range_pattern = False 

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

177 if args.pattern: 

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

179 else: 

180 pattern = "*" 

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

182 n=limit, unique=args.unique) 

183 print_nums = True 

184 elif args.limit is not _unspecified: 

185 n = 10 if limit is None else limit 

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

187 else: 

188 if args.pattern: 

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

190 print_nums = True 

191 hist = history_manager.get_range_by_str( 

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

193 ) 

194 

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

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

197 # misalign. 

198 width = 4 

199 

200 for session, lineno, inline in hist: 

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

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

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

204 # into an editor. 

205 if get_output: 

206 inline, output = inline 

207 if range_pattern: 

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

209 continue 

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

211 

212 multiline = "\n" in inline 

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

214 if print_nums: 

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

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

217 if pyprompts: 

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

219 if multiline: 

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

221 print(inline, file=outfile) 

222 if get_output and output: 

223 print(output, file=outfile) 

224 

225 if close_at_end: 

226 outfile.close() 

227 

228 @line_magic 

229 def recall(self, arg): 

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

231 

232 %recall and %rep are equivalent. 

233 

234 - %recall (no arguments): 

235 

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

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

238 elaborate command lines without using copy-paste:: 

239 

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

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

242 Out[2]: heivaan 

243 In[3]: %recall 

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

245 

246 %recall 45 

247 

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

249 out the number. 

250 

251 %recall 1-4 

252 

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

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

255 

256 %recall foo+bar 

257 

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

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

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

261 placed at the next input prompt. 

262 """ 

263 if not arg: # Last output 

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

265 return 

266 # Get history range 

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

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

269 if cmd: 

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

271 return 

272 

273 try: # Variable in user namespace 

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

275 except Exception: # Search for term in history 

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

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

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

279 continue 

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

281 return 

282 else: 

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

284 return 

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

286 

287 @line_magic 

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

289 """Re-run previous input 

290 

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

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

293 

294 Options: 

295 

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

297 current command. 

298 

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

300 """ 

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

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

303 try: 

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

305 except ValueError: 

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

307 return 

308 

309 if n == 0: 

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

311 return 

312 elif n < 0: 

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

314 return 

315 

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

317 elif "g" in opts: # Search 

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

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

320 for l in reversed(hist): 

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

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

323 break 

324 else: 

325 hist = [] # No matches except %rerun 

326 elif args: # Specify history ranges 

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

328 else: # Last line 

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

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

331 if not hist: 

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

333 return 

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

335 print("=== Executing: ===") 

336 print(histlines) 

337 print("=== Output: ===") 

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