Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Adapt magic commands to new history system. #261

Closed
wants to merge 9 commits into from

3 participants

@takluyver
Owner

This grew from issue ipython/ipython#245. Various magic commands weren't working properly with the new history system: %edit, %macro, and %hist.

Among various minor troubles, selecting a range of lines (%macro test 2-5) numbered from the beginning of the history, so didn't match up with the current line numbers. I've approached this by adding a session_offset attribute to the history manager. This has the added benefit that we no longer need to store a blank history entry so we can count lines from 1.

Along the way, I simplified and modernised parts of the code, including using basestring over StringTypes and .isdigit() over an equivalent regex.

@fperez fperez commented on the diff
IPython/core/history.py
((6 lines not shown))
"""Create a new history manager associated with a shell instance.
+
@fperez Owner
fperez added a note

Docstring should be written with

Parameters
---------------
load_history : bool
 ....

as per our doc guidelines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/core/history.py
@@ -77,6 +80,9 @@ class HistoryManager(object):
# pre-processing. This will allow users to retrieve the input just as
# it was exactly typed in by the user, with %hist -r.
self.input_hist_raw = []
+
+ # Offset so the first line of the current session is #1
+ self.session_offset = -1
@fperez Owner
fperez added a note

Since this is a new attribute, it should be listed at the class level, for details see: http://ipython.scipy.org/doc/nightly/html/development/coding_guide.html#attribute-declarations-for-objects

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@fperez fperez commented on the diff
IPython/core/history.py
((25 lines not shown))
else:
- hist[i] = input_hist[i]
- if not hist:
@fperez Owner
fperez added a note

Why was this if statement removed? Can the condition not happen anymore?

@takluyver Owner

It couldn't happen before, because of the blank first entry in the hist lists (they started as [''], which evaluates as True). With these changes, it can happen if you request the entire history (using index=None) when it's empty. The Qt console requests the entire history when it starts up. To my mind, it makes more sense to return the empty list in that case than to raise an IndexError. The IndexError isn't currently caught anywhere, so it crashes the kernel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@fperez
Owner

This looks great, many thanks! The fixes and cleanups/modernizations are excellent.

I have a few minor notes that I made inline, once those addressed the only other overall concern that I have is whether you could add a couple of small tests. We're trying to be good about adding new (even fairly trivial ones are better than nothing) tests as we retrofit/fix old code. Though I admit that writing a good test for something that depends so much on actual line numbers (like calls to %macro) is tricky... But if you can come up with one, that would be great. If not, no big deal, the code is already a major improvement.

@takluyver
Owner

Alright, I've made the first two changes you suggested, and tried to explain the removal of the if statement. I'll have a look at adding some tests this evening. Thanks for looking over this.

@takluyver
Owner

And there are some tests. I've not attempted to test every bit: %edit, in particular, hasn't got any coverage. But this verifies that the session offset works, and that the %save command picks up on that. There's also a basic test of %macro.

@rkern

Do we have an idea of what we want to do with the In variable? Currently, it just exposes the input_hist_parsed attribute (a plain list) on the history manager without regard to the session offset. We used to have a fancy InputList that would implement slicing by joining the sliced lines together. This was nice for saving out lines to a file.

@fperez
Owner

No, I have to admit I haven't thought this one through very well yet. I suggested to Satra in India we simplify things out by getting rid of the fancy InputList class, looking for a codebase with less custom objects everywhere. But perhaps that was a little bit premature?

Should we revive the InputList object and adjust the code to use it instead? It was really just a simple list subclass with the string joining semantics upon slicing, so bringing it back would be very easy...

I'm totally open to ideas on this front, and sorry if some of the early changes had unintended consequences.

@rkern

Well, the slicing bit is optional (but nice!). The important thing is that In[i] should work for the current session's numbering, however that gets arranged. A custom object is the simplest way to achieve that. It probably should be a non-list object wrapped around input_hist_parsed rather than a list subclass used as input_hist_parsed.

@rkern

That said, the In issue can be dealt with later. This fix should be merged ASAP. It's really annoying!

@fperez
Owner

OK, the changes here look good, but I've just noticed that the actual reloading of previous history sessions gets broken by this branch, so something is amiss. Try opening the Qt console and issuing a few commands, then close it and open it again. The history should reload, and in master it works. But not in this branch...

Let's not merge this until we understand why, and ideally, we add a test that would catch this automatically in the first place...

@takluyver
Owner

OK, I know what it is. The Qt console requests the history from the kernel. With these modifications, requesting the history without specifying a range gets you just this session's history. I'll try to see what the best way to handle that is.

@takluyver takluyver Add option to get_history to determine whether to retrieve the curren…
…t session or the entire history. Qt console on startup requests entire history.
ead117c
@takluyver
Owner

I've added another keyword parameter to get history, this_session=True. The Qt console makes its initial history request with the parameter set to False, and in combination with index=None, this retrieves the entire history, including previous sessions.

While this works, it's beginning to feel a bit inelegant. Should I look at rethinking how history is stored and retrieved? I can do that either in this pull request, or as a separate one. Does anyone have any ideas of how it might best be organised?

@fperez
Owner

Question: what's the status of this pull request now that the sqlite history work is on its way? That's mostly backend work, but I can imagine you may have also made front-side changes in that branch that may override this branch...

@takluyver
Owner

This is superseded by sqlite history, so if we're definitely going down that route, this can be closed, along with #235 and #236. I'd left them open while I was still working to convince people that sqlite history was the way forward.

@takluyver
Owner

This is superseded by SQLite history, which I've just merged.

@takluyver takluyver closed this
@damianavila damianavila referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
120 IPython/core/history.py
@@ -54,6 +54,10 @@ class HistoryManager(object):
# ShadowHist instance with the actual shadow history
shadow_hist = None
+ # Offset so the first line of the current session is #1. Can be
+ # updated after loading history from file.
+ session_offset = -1
+
# Private interface
# Variables used to store the three last inputs from the user. On each new
# history update, we populate the user's namespace with these, shifted as
@@ -65,8 +69,15 @@ class HistoryManager(object):
# call).
_exit_commands = None
- def __init__(self, shell):
+ def __init__(self, shell, load_history=False):
"""Create a new history manager associated with a shell instance.
+
@fperez Owner
fperez added a note

Docstring should be written with

Parameters
---------------
load_history : bool
 ....

as per our doc guidelines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ Parameters
+ ----------
+ load_history: bool, optional
+ If True, history will be loaded from file, and the session
+ offset set, so that the next line entered can be retrieved
+ as #1.
"""
# We need a pointer back to the shell for various tasks.
self.shell = shell
@@ -104,8 +115,9 @@ def __init__(self, shell):
# Object is fully initialized, we can now call methods on it.
- # Fill the history zero entry, user counter starts at 1
- self.store_inputs('\n', '\n')
+ if load_history:
+ self.reload_history()
+ self.session_offset = len(self.input_hist_raw) -1
# Create and start the autosaver.
self.autosave_flag = threading.Event()
@@ -114,6 +126,7 @@ def __init__(self, shell):
# Register the autosave handler to be triggered as a post execute
# callback.
self.shell.register_post_execute(self.autosave_if_due)
+
def _init_shadow_hist(self):
try:
@@ -172,7 +185,7 @@ def reload_history(self):
if self.shell.has_readline:
self.populate_readline_history()
- def get_history(self, index=None, raw=False, output=True):
+ def get_history(self, index=None, raw=False, output=True,this_session=True):
"""Get the history list.
Get the input and output history.
@@ -180,20 +193,22 @@ def get_history(self, index=None, raw=False, output=True):
Parameters
----------
index : n or (n1, n2) or None
- If n, then the last entries. If a tuple, then all in
+ If n, then the last n entries. If a tuple, then all in
range(n1, n2). If None, then all entries. Raises IndexError if
the format of index is incorrect.
raw : bool
If True, return the raw input.
output : bool
If True, then return the output as well.
+ this_session : bool
+ If True, indexing is from 1 at the start of this session.
+ If False, indexing is from 1 at the start of the whole history.
Returns
-------
If output is True, then return a dict of tuples, keyed by the prompt
numbers and with values of (input, output). If output is False, then
- a dict, keyed by the prompt number with the values of input. Raises
- IndexError if no history is found.
+ a dict, keyed by the prompt number with the values of input.
"""
if raw:
input_hist = self.input_hist_raw
@@ -201,24 +216,29 @@ def get_history(self, index=None, raw=False, output=True):
input_hist = self.input_hist_parsed
if output:
output_hist = self.output_hist
+
+ if this_session:
+ offset = self.session_offset
+ else:
+ offset = -1
+
n = len(input_hist)
if index is None:
- start=0; stop=n
+ start=offset+1; stop=n
elif isinstance(index, int):
start=n-index; stop=n
- elif isinstance(index, tuple) and len(index) == 2:
- start=index[0]; stop=index[1]
+ elif len(index) == 2:
+ start = index[0] + offset
+ stop = index[1] + offset
else:
raise IndexError('Not a valid index for the input history: %r'
% index)
hist = {}
for i in range(start, stop):
if output:
- hist[i] = (input_hist[i], output_hist.get(i))
+ hist[i-offset] = (input_hist[i], output_hist.get(i-offset))
else:
- hist[i] = input_hist[i]
- if not hist:
@fperez Owner
fperez added a note

Why was this if statement removed? Can the condition not happen anymore?

@takluyver Owner

It couldn't happen before, because of the blank first entry in the hist lists (they started as [''], which evaluates as True). With these changes, it can happen if you request the entire history (using index=None) when it's empty. The Qt console requests the entire history when it starts up. To my mind, it makes more sense to return the empty list in that case than to raise an IndexError. The IndexError isn't currently caught anywhere, so it crashes the kernel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
- raise IndexError('No history for range of indices: %r' % index)
+ hist[i-offset] = input_hist[i]
return hist
def store_inputs(self, source, source_raw=None):
@@ -271,6 +291,8 @@ def reset(self):
self.output_hist.clear()
# The directory history can't be completely empty
self.dir_hist[:] = [os.getcwd()]
+ # Reset session offset to -1, so next command counts as #1
+ self.session_offset = -1
class HistorySaveThread(threading.Thread):
"""This thread makes IPython save history periodically.
@@ -353,6 +375,9 @@ def magic_history(self, parameter_s = ''):
print('This feature is only available if numbered prompts are in use.')
return
opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
+
+ # For brevity
+ history_manager = self.shell.history_manager
# Check if output to specific file was requested.
try:
@@ -369,47 +394,41 @@ def magic_history(self, parameter_s = ''):
outfile = open(outfname,'w')
close_at_end = True
-
- if 't' in opts:
- input_hist = self.shell.history_manager.input_hist_parsed
- elif 'r' in opts:
- input_hist = self.shell.history_manager.input_hist_raw
- else:
- # Raw history is the default
- input_hist = self.shell.history_manager.input_hist_raw
+
+ print_nums = 'n' in opts
+ print_outputs = 'o' in opts
+ pyprompts = 'p' in opts
+ # Raw history is the default
+ raw = not('t' in opts)
default_length = 40
pattern = None
if 'g' in opts:
- init = 1
- final = len(input_hist)
+ index = None
parts = parameter_s.split(None, 1)
if len(parts) == 1:
parts += '*'
head, pattern = parts
pattern = "*" + pattern + "*"
elif len(args) == 0:
- final = len(input_hist)-1
- init = max(1,final-default_length)
+ index = None
elif len(args) == 1:
- final = len(input_hist)
- init = max(1, final-int(args[0]))
+ index = int(args[0])
elif len(args) == 2:
- init, final = map(int, args)
+ index = map(int, args)
else:
warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout)
return
+
+ hist = history_manager.get_history(index, raw, print_outputs)
- width = len(str(final))
+ width = len(str(max(hist.iterkeys())))
line_sep = ['','\n']
- print_nums = 'n' in opts
- print_outputs = 'o' in opts
- pyprompts = 'p' in opts
found = False
if pattern is not None:
- sh = self.shell.history_manager.shadowhist.all()
+ sh = history_manager.shadow_hist.all()
for idx, s in sh:
if fnmatch.fnmatch(s, pattern):
print("0%d: %s" %(idx, s.expandtabs(4)), file=outfile)
@@ -421,41 +440,34 @@ def magic_history(self, parameter_s = ''):
file=outfile)
print("=== start of normal history ===", file=outfile)
- for in_num in range(init, final):
+ for in_num, inline in sorted(hist.iteritems()):
# Print user history with tabs expanded to 4 spaces. The GUI clients
# use hard tabs for easier usability in auto-indented code, but we want
# to produce PEP-8 compliant history for safe pasting into an editor.
- inline = input_hist[in_num].expandtabs(4).rstrip()+'\n'
+ if print_outputs:
+ inline, output = inline
+ inline = inline.expandtabs(4).rstrip()
if pattern is not None and not fnmatch.fnmatch(inline, pattern):
continue
- multiline = int(inline.count('\n') > 1)
+ multiline = "\n" in inline
if print_nums:
print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
- file=outfile)
+ file=outfile, end='')
if pyprompts:
- print('>>>', file=outfile)
+ print(">>> ", end="", file=outfile)
if multiline:
- lines = inline.splitlines()
- print('\n... '.join(lines), file=outfile)
- print('... ', file=outfile)
- else:
- print(inline, end='', file=outfile)
- else:
- print(inline, end='', file=outfile)
- if print_outputs:
- output = self.shell.history_manager.output_hist.get(in_num)
- if output is not None:
- print(repr(output), file=outfile)
+ inline = "\n... ".join(inline.splitlines()) + "\n..."
+ print(inline, file=outfile)
+ if print_outputs and output:
+ print(repr(output), file=outfile)
if close_at_end:
outfile.close()
-
-def magic_hist(self, parameter_s=''):
- """Alternate name for %history."""
- return self.magic_history(parameter_s)
+# %hist is an alternative name
+magic_hist = magic_history
def rep_f(self, arg):
View
13 IPython/core/interactiveshell.py
@@ -1248,7 +1248,7 @@ def object_inspect(self, oname):
def init_history(self):
"""Sets up the command history, and starts regular autosaves."""
- self.history_manager = HistoryManager(shell=self)
+ self.history_manager = HistoryManager(shell=self, load_history=True)
def save_history(self):
"""Save input history to a file (via readline library)."""
@@ -1277,8 +1277,8 @@ def wrapper():
self.reload_history()
return wrapper
- def get_history(self, index=None, raw=False, output=True):
- return self.history_manager.get_history(index, raw, output)
+ def get_history(self, index=None, raw=False, output=True,this_session=True):
+ return self.history_manager.get_history(index, raw, output,this_session)
#-------------------------------------------------------------------------
@@ -1560,11 +1560,8 @@ def init_readline(self):
readline.set_completer_delims(delims)
# otherwise we end up with a monster history after a while:
readline.set_history_length(self.history_length)
- try:
- #print '*** Reading readline history' # dbg
- self.reload_history()
- except IOError:
- pass # It doesn't exist yet.
+
+ self.history_manager.populate_readline_history()
# Configure auto-indent for all platforms
self.set_autoindent(self.autoindent)
View
4 IPython/core/macro.py
@@ -19,9 +19,9 @@ class Macro(IPyAutocall):
Args to macro are available in _margv list if you need them.
"""
- def __init__(self,data):
+ def __init__(self,code):
"""store the macro value, as a single string which can be executed"""
- self.value = ''.join(data).rstrip()+'\n'
+ self.value = code.rstrip()+'\n'
def __str__(self):
return self.value
View
57 IPython/core/magic.py
@@ -57,7 +57,7 @@
from IPython.utils.path import get_py_filename
from IPython.utils.process import arg_split, abbrev_cwd
from IPython.utils.terminal import set_term_title
-from IPython.utils.text import LSString, SList, StringTypes, format_screen
+from IPython.utils.text import LSString, SList, format_screen
from IPython.utils.timing import clock, clock2
from IPython.utils.warn import warn, error
from IPython.utils.ipstruct import Struct
@@ -184,11 +184,7 @@ def extract_input_slices(self,slices,raw=False):
N:M -> standard python form, means including items N...(M-1).
N-M -> include items N..M (closed endpoint)."""
-
- if raw:
- hist = self.shell.history_manager.input_hist_raw
- else:
- hist = self.shell.history_manager.input_hist_parsed
+ history_manager = self.shell.history_manager
cmds = []
for chunk in slices:
@@ -200,7 +196,8 @@ def extract_input_slices(self,slices,raw=False):
else:
ini = int(chunk)
fin = ini+1
- cmds.append(''.join(hist[ini:fin]))
+ hist = history_manager.get_history((ini,fin), raw=raw, output=False)
+ cmds.append('\n'.join(hist[i] for i in sorted(hist.iterkeys())))
return cmds
def arg_err(self,func):
@@ -1967,18 +1964,17 @@ def magic_macro(self,parameter_s = ''):
In [60]: exec In[44:48]+In[49]"""
opts,args = self.parse_options(parameter_s,'r',mode='list')
- if not args:
- macs = [k for k,v in self.shell.user_ns.items() if isinstance(v, Macro)]
- macs.sort()
- return macs
+ if not args: # List existing macros
+ return sorted(k for k,v in self.shell.user_ns.iteritems() if\
+ isinstance(v, Macro))
if len(args) == 1:
raise UsageError(
"%macro insufficient args; usage '%macro name n1-n2 n3-4...")
name,ranges = args[0], args[1:]
#print 'rng',ranges # dbg
- lines = self.extract_input_slices(ranges,opts.has_key('r'))
- macro = Macro(lines)
+ lines = self.extract_input_slices(ranges,'r' in opts)
+ macro = Macro("\n".join(lines))
self.shell.define_macro(name, macro)
print 'Macro `%s` created. To execute, type its name (without quotes).' % name
print 'Macro contents:'
@@ -2013,10 +2009,9 @@ def magic_save(self,parameter_s = ''):
if ans.lower() not in ['y','yes']:
print 'Operation cancelled.'
return
- cmds = ''.join(self.extract_input_slices(ranges,opts.has_key('r')))
- f = file(fname,'w')
- f.write(cmds)
- f.close()
+ cmds = '\n'.join(self.extract_input_slices(ranges, 'r' in opts))
+ with open(fname,'w') as f:
+ f.write(cmds)
print 'The following commands were written to file `%s`:' % fname
print cmds
@@ -2222,26 +2217,26 @@ class DataIsObject(Exception): pass
# by default this is done with temp files, except when the given
# arg is a filename
- use_temp = 1
+ use_temp = True
- if re.match(r'\d',args):
+ data = ''
+ if args[0].isdigit():
# Mode where user specifies ranges of lines, like in %macro.
# This means that you can't edit files whose names begin with
# numbers this way. Tough.
ranges = args.split()
- data = ''.join(self.extract_input_slices(ranges,opts_r))
+ data = '\n'.join(self.extract_input_slices(ranges,opts_r))
elif args.endswith('.py'):
filename = make_filename(args)
- data = ''
- use_temp = 0
+ use_temp = False
elif args:
try:
# Load the parameter given as a variable. If not a string,
# process it as an object instead (below)
#print '*** args',args,'type',type(args) # dbg
- data = eval(args,self.shell.user_ns)
- if not type(data) in StringTypes:
+ data = eval(args, self.shell.user_ns)
+ if not isinstance(data, basestring):
raise DataIsObject
except (NameError,SyntaxError):
@@ -2251,13 +2246,11 @@ class DataIsObject(Exception): pass
warn("Argument given (%s) can't be found as a variable "
"or as a filename." % args)
return
-
- data = ''
- use_temp = 0
+ use_temp = False
+
except DataIsObject:
-
# macros have a special edit function
- if isinstance(data,Macro):
+ if isinstance(data, Macro):
self._edit_macro(args,data)
return
@@ -2296,9 +2289,7 @@ class DataIsObject(Exception): pass
warn('The file `%s` where `%s` was defined cannot '
'be read.' % (filename,data))
return
- use_temp = 0
- else:
- data = ''
+ use_temp = False
if use_temp:
filename = self.shell.mktempfile(data)
@@ -2321,7 +2312,7 @@ class DataIsObject(Exception): pass
if args.strip() == 'pasted_block':
self.shell.user_ns['pasted_block'] = file_read(filename)
- if opts.has_key('x'): # -x prevents actual execution
+ if 'x' in opts: # -x prevents actual execution
print
else:
print 'done. Executing edited code...'
View
21 IPython/core/tests/test_history.py
@@ -30,11 +30,11 @@ def test_history():
ip.history_manager = HistoryManager(ip)
ip.history_manager.hist_file = histfile
print 'test',histfile
- hist = ['a=1\n', 'def f():\n test = 1\n return test\n', 'b=2\n']
+ hist = ['a=1', 'def f():\n test = 1\n return test', 'b=2']
# test save and load
ip.history_manager.input_hist_raw[:] = []
for h in hist:
- ip.history_manager.input_hist_raw.append(h)
+ ip.history_manager.store_inputs(h)
ip.save_history()
ip.history_manager.input_hist_raw[:] = []
ip.reload_history()
@@ -43,6 +43,23 @@ def test_history():
nt.assert_equal(len(ip.history_manager.input_hist_raw), len(hist))
for i,h in enumerate(hist):
nt.assert_equal(hist[i], ip.history_manager.input_hist_raw[i])
+
+ # Test that session offset works.
+ ip.history_manager.session_offset = \
+ len(ip.history_manager.input_hist_raw) -1
+ newcmds = ["z=5","class X(object):\n pass", "k='p'"]
+ for cmd in newcmds:
+ ip.history_manager.store_inputs(cmd)
+ gothist = ip.history_manager.get_history((1,4),
+ raw=True, output=False)
+ nt.assert_equal(gothist, dict(zip([1,2,3], newcmds)))
+
+ # Cross testing: check that magic %save picks up on the session
+ # offset.
+ testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
+ ip.magic_save(testfilename + " 1-3")
+ testfile = open(testfilename, "r")
+ nt.assert_equal(testfile.read(), "\n".join(newcmds))
finally:
# Restore history manager
ip.history_manager = hist_manager_ori
View
12 IPython/core/tests/test_magic.py
@@ -173,6 +173,18 @@ def test_shist():
yield nt.assert_equal,s.get(2),'world'
shutil.rmtree(tfile)
+
+def test_macro():
+ ip = get_ipython()
+ ip.history_manager.reset() # Clear any existing history.
+ cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
+ for cmd in cmds:
+ ip.history_manager.store_inputs(cmd)
+ ip.magic("macro test 1-3")
+ nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
+
+ # List macros.
+ assert "test" in ip.magic("macro")
# XXX failing for now, until we get clearcmd out of quarantine. But we should
View
3  IPython/frontend/qt/console/ipython_widget.py
@@ -217,7 +217,8 @@ def _started_channels(self):
""" Reimplemented to make a history request.
"""
super(IPythonWidget, self)._started_channels()
- self.kernel_manager.xreq_channel.history(raw=True, output=False)
+ self.kernel_manager.xreq_channel.history(raw=True, output=False,
+ this_session=False)
#---------------------------------------------------------------------------
# 'ConsoleWidget' public interface
View
7 IPython/utils/text.py
@@ -19,7 +19,6 @@
import os
import re
import shutil
-import types
from IPython.external.path import path
@@ -30,8 +29,6 @@
# Code
#-----------------------------------------------------------------------------
-StringTypes = types.StringTypes
-
def unquote_ends(istr):
"""Remove a single pair of quotes from the endpoints of a string."""
@@ -325,7 +322,7 @@ def qw(words,flat=0,sep=None,maxsplit=-1):
['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
"""
- if type(words) in StringTypes:
+ if isinstance(words, basestring):
return [word.strip() for word in words.split(sep,maxsplit)
if word and not word.isspace() ]
if flat:
@@ -345,7 +342,7 @@ def qw_lol(indata):
We need this to make sure the modules_some keys *always* end up as a
list of lists."""
- if type(indata) in StringTypes:
+ if isinstance(indata, basestring):
return [qw(indata)]
else:
return qw(indata)
View
7 IPython/zmq/ipkernel.py
@@ -301,10 +301,9 @@ def object_info_request(self, ident, parent):
io.raw_print(msg)
def history_request(self, ident, parent):
- output = parent['content']['output']
- index = parent['content']['index']
- raw = parent['content']['raw']
- hist = self.shell.get_history(index=index, raw=raw, output=output)
+ # parent['content'] should contain keys "index", "raw", "output" and
+ # "this_session".
+ hist = self.shell.get_history(**parent['content'])
content = {'history' : hist}
msg = self.session.send(self.reply_socket, 'history_reply',
content, parent, ident)
View
8 IPython/zmq/kernelmanager.py
@@ -281,7 +281,7 @@ def object_info(self, oname):
self._queue_request(msg)
return msg['header']['msg_id']
- def history(self, index=None, raw=False, output=True):
+ def history(self, index=None, raw=False, output=True, this_session=True):
"""Get the history list.
Parameters
@@ -294,12 +294,16 @@ def history(self, index=None, raw=False, output=True):
If True, return the raw input.
output : bool
If True, then return the output as well.
+ this_session : bool
+ If True, returns only history from the current session. Otherwise,
+ includes reloaded history from previous sessions.
Returns
-------
The msg_id of the message sent.
"""
- content = dict(index=index, raw=raw, output=output)
+ content = dict(index=index, raw=raw, output=output,
+ this_session=this_session)
msg = self.session.msg('history_request', content)
self._queue_request(msg)
return msg['header']['msg_id']
View
26 IPython/zmq/zmqshell.py
@@ -18,7 +18,6 @@
# Stdlib
import inspect
import os
-import re
# Our own
from IPython.core.interactiveshell import (
@@ -31,7 +30,6 @@
from IPython.core.payloadpage import install_payload_page
from IPython.utils import io
from IPython.utils.path import get_py_filename
-from IPython.utils.text import StringTypes
from IPython.utils.traitlets import Instance, Type, Dict
from IPython.utils.warn import warn
from IPython.zmq.session import extract_header
@@ -433,9 +431,10 @@ class DataIsObject(Exception): pass
# by default this is done with temp files, except when the given
# arg is a filename
- use_temp = 1
+ use_temp = True
- if re.match(r'\d',args):
+ data = ''
+ if args[0].isdigit():
# Mode where user specifies ranges of lines, like in %macro.
# This means that you can't edit files whose names begin with
# numbers this way. Tough.
@@ -443,16 +442,15 @@ class DataIsObject(Exception): pass
data = ''.join(self.extract_input_slices(ranges,opts_r))
elif args.endswith('.py'):
filename = make_filename(args)
- data = ''
- use_temp = 0
+ use_temp = False
elif args:
try:
# Load the parameter given as a variable. If not a string,
# process it as an object instead (below)
#print '*** args',args,'type',type(args) # dbg
- data = eval(args,self.shell.user_ns)
- if not type(data) in StringTypes:
+ data = eval(args, self.shell.user_ns)
+ if not isinstance(data, basestring):
raise DataIsObject
except (NameError,SyntaxError):
@@ -462,13 +460,11 @@ class DataIsObject(Exception): pass
warn("Argument given (%s) can't be found as a variable "
"or as a filename." % args)
return
-
- data = ''
- use_temp = 0
+ use_temp = False
+
except DataIsObject:
-
# macros have a special edit function
- if isinstance(data,Macro):
+ if isinstance(data, Macro):
self._edit_macro(args,data)
return
@@ -507,9 +503,7 @@ class DataIsObject(Exception): pass
warn('The file `%s` where `%s` was defined cannot '
'be read.' % (filename,data))
return
- use_temp = 0
- else:
- data = ''
+ use_temp = False
if use_temp:
filename = self.shell.mktempfile(data)
Something went wrong with that request. Please try again.