##// END OF EJS Templates
Merge pull request #13049 from MrMino/empty_histrange_means_all...
Matthias Bussonnier -
r26671:be4887fe merge
parent child Browse files
Show More
@@ -0,0 +1,19 b''
1 Empty History Ranges
2 ====================
3
4 A number of magics that take history ranges can now be used with an empty
5 range. These magics are:
6
7 * ``%save``
8 * ``%load``
9 * ``%pastebin``
10 * ``%pycat``
11
12 Using them this way will make them take the history of the current session up
13 to the point of the magic call (such that the magic itself will not be
14 included).
15
16 Therefore it is now possible to save the whole history to a file using simple
17 ``%save <filename>``, load and edit it using ``%load`` (makes for a nice usage
18 when followed with :kbd:`F2`), send it to dpaste.org using ``%pastebin``, or
19 view the whole thing syntax-highlighted with a single ``%pycat``.
@@ -445,8 +445,11 b' class HistoryAccessor(HistoryAccessorBase):'
445 445 Parameters
446 446 ----------
447 447 rangestr : str
448 A string specifying ranges, e.g. "5 ~2/1-4". See
449 :func:`magic_history` for full details.
448 A string specifying ranges, e.g. "5 ~2/1-4". If empty string is used,
449 this will return everything from current session's history.
450
451 See the documentation of :func:`%history` for the full details.
452
450 453 raw, output : bool
451 454 As :meth:`get_range`
452 455
@@ -851,11 +854,18 b' $""", re.VERBOSE)'
851 854 def extract_hist_ranges(ranges_str):
852 855 """Turn a string of history ranges into 3-tuples of (session, start, stop).
853 856
857 Empty string results in a `[(0, 1, None)]`, i.e. "everything from current
858 session".
859
854 860 Examples
855 861 --------
856 862 >>> list(extract_hist_ranges("~8/5-~7/4 2"))
857 863 [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
858 864 """
865 if ranges_str == "":
866 yield (0, 1, None) # Everything from current session
867 return
868
859 869 for range_str in ranges_str.split():
860 870 rmatch = range_re.match(range_str)
861 871 if not rmatch:
@@ -3696,12 +3696,15 b' class InteractiveShell(SingletonConfigurable):'
3696 3696
3697 3697 Parameters
3698 3698 ----------
3699 range_str : string
3699 range_str : str
3700 3700 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3701 3701 since this function is for use by magic functions which get their
3702 3702 arguments as strings. The number before the / is the session
3703 3703 number: ~n goes n back from the current session.
3704 3704
3705 If empty string is given, returns history of current session
3706 without the last input.
3707
3705 3708 raw : bool, optional
3706 3709 By default, the processed input is used. If this is true, the raw
3707 3710 input history is used instead.
@@ -3715,7 +3718,16 b' class InteractiveShell(SingletonConfigurable):'
3715 3718 * ``N-M`` -> include items N..M (closed endpoint).
3716 3719 """
3717 3720 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3718 return "\n".join(x for _, _, x in lines)
3721 text = "\n".join(x for _, _, x in lines)
3722
3723 # Skip the last line, as it's probably the magic that called this
3724 if not range_str:
3725 if "\n" not in text:
3726 text = ""
3727 else:
3728 text = text[: text.rfind("\n")]
3729
3730 return text
3719 3731
3720 3732 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3721 3733 """Get a code string from history, file, url, or a string or macro.
@@ -3724,14 +3736,15 b' class InteractiveShell(SingletonConfigurable):'
3724 3736
3725 3737 Parameters
3726 3738 ----------
3727
3728 3739 target : str
3729
3730 3740 A string specifying code to retrieve. This will be tried respectively
3731 3741 as: ranges of input history (see %history for syntax), url,
3732 3742 corresponding .py file, filename, or an expression evaluating to a
3733 3743 string or Macro in the user namespace.
3734 3744
3745 If empty string is given, returns complete history of current
3746 session, without the last line.
3747
3735 3748 raw : bool
3736 3749 If true (default), retrieve raw history. Has no effect on the other
3737 3750 retrieval mechanisms.
@@ -202,6 +202,9 b' class CodeMagics(Magics):'
202 202 This function uses the same syntax as %history for input ranges,
203 203 then saves the lines to the filename you specify.
204 204
205 If no ranges are specified, saves history of the current session up to
206 this point.
207
205 208 It adds a '.py' extension to the file if you don't do so yourself, and
206 209 it asks for confirmation before overwriting existing files.
207 210
@@ -254,6 +257,9 b' class CodeMagics(Magics):'
254 257 The argument can be an input history range, a filename, or the name of a
255 258 string or macro.
256 259
260 If no arguments are given, uploads the history of this session up to
261 this point.
262
257 263 Options:
258 264
259 265 -d: Pass a custom description. The default will say
@@ -315,6 +321,9 b' class CodeMagics(Magics):'
315 321 where source can be a filename, URL, input history range, macro, or
316 322 element in the user namespace
317 323
324 If no arguments are given, loads the history of this session up to this
325 point.
326
318 327 Options:
319 328
320 329 -r <lines>: Specify lines or ranges of lines to load from the source.
@@ -333,6 +342,7 b' class CodeMagics(Magics):'
333 342 confirmation before loading source with more than 200 000 characters, unless
334 343 -y flag is passed or if the frontend does not support raw_input::
335 344
345 %load
336 346 %load myscript.py
337 347 %load 7-27
338 348 %load myMacro
@@ -344,13 +354,7 b' class CodeMagics(Magics):'
344 354 %load -n my_module.wonder_function
345 355 """
346 356 opts,args = self.parse_options(arg_s,'yns:r:')
347
348 if not args:
349 raise UsageError('Missing filename, URL, input history range, '
350 'macro, or element in the user namespace.')
351
352 357 search_ns = 'n' in opts
353
354 358 contents = self.shell.find_user_code(args, search_ns=search_ns)
355 359
356 360 if 's' in opts:
@@ -184,14 +184,12 b' class HistoryMagics(Magics):'
184 184 n = 10 if limit is None else limit
185 185 hist = history_manager.get_tail(n, raw=raw, output=get_output)
186 186 else:
187 if args.range: # Get history by ranges
188 if args.pattern:
189 range_pattern = "*" + " ".join(args.pattern) + "*"
190 print_nums = True
191 hist = history_manager.get_range_by_str(" ".join(args.range),
192 raw, get_output)
193 else: # Just get history for the current session
194 hist = history_manager.get_range(raw=raw, output=get_output)
187 if args.pattern:
188 range_pattern = "*" + " ".join(args.pattern) + "*"
189 print_nums = True
190 hist = history_manager.get_range_by_str(
191 " ".join(args.range), raw, get_output
192 )
195 193
196 194 # We could be displaying the entire history, so let's not try to pull
197 195 # it into a list in memory. Anything that needs more space will just
@@ -806,18 +806,17 b' class OSMagics(Magics):'
806 806 to be Python source and will show it with syntax highlighting.
807 807
808 808 This magic command can either take a local filename, an url,
809 an history range (see %history) or a macro as argument ::
809 an history range (see %history) or a macro as argument.
810
811 If no parameter is given, prints out history of current session up to
812 this point. ::
810 813
811 814 %pycat myscript.py
812 815 %pycat 7-27
813 816 %pycat myMacro
814 817 %pycat http://www.example.com/myscript.py
815 818 """
816 if not parameter_s:
817 raise UsageError('Missing filename, URL, input history range, '
818 'or macro.')
819
820 try :
819 try:
821 820 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
822 821 except (ValueError, IOError):
823 822 print("Error: no such file, variable, URL, history range or macro")
@@ -160,6 +160,14 b' def test_extract_hist_ranges():'
160 160 actual = list(extract_hist_ranges(instr))
161 161 nt.assert_equal(actual, expected)
162 162
163
164 def test_extract_hist_ranges_empty_str():
165 instr = ""
166 expected = [(0, 1, None)] # 0 == current session, None == to end
167 actual = list(extract_hist_ranges(instr))
168 nt.assert_equal(actual, expected)
169
170
163 171 def test_magic_rerun():
164 172 """Simple test for %rerun (no args -> rerun last line)"""
165 173 ip = get_ipython()
@@ -1089,6 +1089,29 b' def test_save():'
1089 1089 nt.assert_in("coding: utf-8", content)
1090 1090
1091 1091
1092 def test_save_with_no_args():
1093 ip = get_ipython()
1094 ip.history_manager.reset() # Clear any existing history.
1095 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())", "%save"]
1096 for i, cmd in enumerate(cmds, start=1):
1097 ip.history_manager.store_inputs(i, cmd)
1098
1099 with TemporaryDirectory() as tmpdir:
1100 path = os.path.join(tmpdir, "testsave.py")
1101 ip.run_line_magic("save", path)
1102 content = Path(path).read_text()
1103 expected_content = dedent(
1104 """\
1105 # coding: utf-8
1106 a=1
1107 def b():
1108 return a**2
1109 print(a, b())
1110 """
1111 )
1112 nt.assert_equal(content, expected_content)
1113
1114
1092 1115 def test_store():
1093 1116 """Test %store."""
1094 1117 ip = get_ipython()
General Comments 0
You need to be logged in to leave comments. Login now