Skip to content

Commit

Permalink
Merge pull request #4542 from ivanov/history-clear
Browse files Browse the repository at this point in the history
new `ipython history clear` subcommand

This new subcommand is equivalent to ipython history trim --HistoryTrim.keep=0, which is now supported (and also has a more convenient --keep alias)

This command comes with a fix to bash completion of flags for ipython history subcmd

also included is a tiny fix for nbconvert completion that was pointed out by @jakobgager in #4528

also included is a change to our utils.io.ask_yes_no function that allows for specifying the behavior of a KeyboardInterrupt.
  • Loading branch information
minrk committed Nov 22, 2013
2 parents b6dce27 + 279ccc9 commit 24e1056
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 21 deletions.
66 changes: 53 additions & 13 deletions IPython/core/historyapp.py
Expand Up @@ -12,13 +12,25 @@
from IPython.config.application import Application
from IPython.core.application import BaseIPythonApplication
from IPython.utils.traitlets import Bool, Int, Dict
from IPython.utils.io import ask_yes_no

trim_hist_help = """Trim the IPython history database to the last 1000 entries.
This actually copies the last 1000 entries to a new database, and then replaces
the old file with the new.
the old file with the new. Use the `--keep=` argument to specify a number
other than 1000.
"""

clear_hist_help = """Clear the IPython history database, deleting all entries.
Because this is a destructive operation, IPython will prompt the user if they
really want to do this. Passing a `-f` flag will force clearing without a
prompt.
This is an handy alias to `ipython history trim --keep=0`
"""


class HistoryTrim(BaseIPythonApplication):
description = trim_hist_help

Expand All @@ -30,9 +42,13 @@ class HistoryTrim(BaseIPythonApplication):

flags = Dict(dict(
backup = ({'HistoryTrim' : {'backup' : True}},
"Set Application.log_level to 0, maximizing log output."
backup.get_metadata('help')
)
))

aliases=Dict(dict(
keep = 'HistoryTrim.keep'
))

def start(self):
profile_dir = self.profile_dir.location
Expand All @@ -44,18 +60,19 @@ def start(self):
'history ORDER BY session DESC, line DESC LIMIT ?', (self.keep+1,)))
if len(inputs) <= self.keep:
print("There are already at most %d entries in the history database." % self.keep)
print("Not doing anything.")
print("Not doing anything. Use --keep= argument to keep fewer entries")
return

print("Trimming history to the most recent %d entries." % self.keep)

inputs.pop() # Remove the extra element we got to check the length.
inputs.reverse()
first_session = inputs[0][0]
outputs = list(con.execute('SELECT session, line, output FROM '
'output_history WHERE session >= ?', (first_session,)))
sessions = list(con.execute('SELECT session, start, end, num_cmds, remark FROM '
'sessions WHERE session >= ?', (first_session,)))
if inputs:
first_session = inputs[0][0]
outputs = list(con.execute('SELECT session, line, output FROM '
'output_history WHERE session >= ?', (first_session,)))
sessions = list(con.execute('SELECT session, start, end, num_cmds, remark FROM '
'sessions WHERE session >= ?', (first_session,)))
con.close()

# Create the new history database.
Expand All @@ -78,11 +95,12 @@ def start(self):
new_db.commit()


with new_db:
# Add the recent history into the new database.
new_db.executemany('insert into sessions values (?,?,?,?,?)', sessions)
new_db.executemany('insert into history values (?,?,?,?)', inputs)
new_db.executemany('insert into output_history values (?,?,?)', outputs)
if inputs:
with new_db:
# Add the recent history into the new database.
new_db.executemany('insert into sessions values (?,?,?,?,?)', sessions)
new_db.executemany('insert into history values (?,?,?,?)', inputs)
new_db.executemany('insert into output_history values (?,?,?)', outputs)
new_db.close()

if self.backup:
Expand All @@ -98,13 +116,35 @@ def start(self):

os.rename(new_hist_file, hist_file)

class HistoryClear(HistoryTrim):
description = clear_hist_help
keep = Int(0, config=False,
help="Number of recent lines to keep in the database.")

force = Bool(False, config=True,
help="Don't prompt user for confirmation")

flags = Dict(dict(
force = ({'HistoryClear' : {'force' : True}},
force.get_metadata('help')),
f = ({'HistoryTrim' : {'force' : True}},
force.get_metadata('help')
)
))
aliases = Dict()

def start(self):
if self.force or ask_yes_no("Really delete all ipython history? ",
default="no", interrupt="no"):
HistoryTrim.start(self)

class HistoryApp(Application):
name = u'ipython-history'
description = "Manage the IPython history database."

subcommands = Dict(dict(
trim = (HistoryTrim, HistoryTrim.description.splitlines()[0]),
clear = (HistoryClear, HistoryClear.description.splitlines()[0]),
))

def start(self):
Expand Down
9 changes: 6 additions & 3 deletions IPython/utils/io.py
Expand Up @@ -155,11 +155,13 @@ def __del__(self):
self.close()


def ask_yes_no(prompt,default=None):
def ask_yes_no(prompt, default=None, interrupt=None):
"""Asks a question and returns a boolean (y/n) answer.
If default is given (one of 'y','n'), it is used if the user input is
empty. Otherwise the question is repeated until an answer is given.
empty. If interrupt is given (one of 'y','n'), it is used if the user
presses Ctrl-C. Otherwise the question is repeated until an answer is
given.
An EOF is treated as the default answer. If there is no default, an
exception is raised to prevent infinite loops.
Expand All @@ -174,7 +176,8 @@ def ask_yes_no(prompt,default=None):
if not ans: # response was an empty string
ans = default
except KeyboardInterrupt:
pass
if interrupt:
ans = interrupt
except EOFError:
if default in answers.keys():
ans = default
Expand Down
1 change: 1 addition & 0 deletions docs/source/whatsnew/pr/bash-completion.rst
@@ -0,0 +1 @@
* bash completion updated with support for all ipython subcommands and flags, including nbconvert
4 changes: 4 additions & 0 deletions docs/source/whatsnew/pr/history-clear.rst
@@ -0,0 +1,4 @@
* ``ipython history trim``: added ``--keep=<N>`` as an alias for the more verbose
``--HistoryTrim.keep=<N>``
* new ``ipython history clear`` subcommand, which is the same as the newly supported
``ipython history trim --keep=0``
26 changes: 21 additions & 5 deletions examples/core/ipython-completion.bash
Expand Up @@ -24,7 +24,7 @@ _ipython()
{
local cur=${COMP_WORDS[COMP_CWORD]}
local prev=${COMP_WORDS[COMP_CWORD - 1]}
local subcommands="notebook qtconsole console kernel profile locate history nbconvert"
local subcommands="notebook qtconsole console kernel profile locate history nbconvert "
local opts=""
if [ -z "$__ipython_complete_baseopts" ]; then
_ipython_get_flags baseopts
Expand All @@ -46,12 +46,21 @@ _ipython()

if [[ ${cur} == -* ]]; then
case $mode in
"notebook" | "qtconsole" | "console" | "kernel")
"notebook" | "qtconsole" | "console" | "kernel" | "nbconvert")
_ipython_get_flags $mode
opts=$"${opts} ${baseopts}"
;;
"locate" | "history" | "profile")
"locate" | "profile")
_ipython_get_flags $mode
;;
"history")
if [[ $COMP_CWORD -ge 3 ]]; then
# 'history trim' and 'history clear' covered by next line
_ipython_get_flags history\ "${COMP_WORDS[2]}"
else
_ipython_get_flags $mode

fi
opts=$"${opts}"
;;
*)
Expand All @@ -62,10 +71,17 @@ _ipython()
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
elif [[ $mode == "profile" ]]; then
opts="list create locate"
opts="list create locate "
local IFS=$'\t\n'
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
elif [[ $mode == "history" ]]; then
opts="trim"
if [[ $COMP_CWORD -ge 3 ]]; then
# drop into flags
opts="--"
else
opts="trim clear "
fi
local IFS=$'\t\n'
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
elif [[ $mode == "locate" ]]; then
opts="profile"
Expand Down

0 comments on commit 24e1056

Please sign in to comment.