как я могу избежать сохранения команды в истории ipython?

В bash я могу предотвратить сохранение команды в истории bash, поставив перед ней пробел. Я не могу использовать этот метод в ipython. Как бы я сделал эквивалент в ipython?


person Andrew    schedule 29.01.2016    source источник
comment
Связано: stackoverflow. ком/вопросы/19606275/   -  person ShreevatsaR    schedule 22.11.2016


Ответы (3)


Примечание об устаревании: это было написано для IPython 4.0.1. Начиная с версии 5 IPython больше не использует readline.


Нет стандартного способа, можно добавить или обойти.

В IPython есть два вида истории:

  • readline история. Он доступен с помощью специальных клавиш/комбинаций клавиш (вверх/вниз, Ctrl-R и т.д.). Сохраняет только строки, введенные (с <Enter>) на консоли (или, в pyreadline, также вставленные из буфера обмена). IPython опирается на локальную реализацию Python readline API, которая не имеет "не добавлять" и обычно добавляет каждую строку в историю.
    У IPython есть средство, чтобы облегчить это, IPython.core.interactiveshell.ReadlineNoRecord, менеджер контекста, который делает моментальный снимок истории, а затем восстанавливает ее. Начиная с ipython 4.0.1, он используется только магией %run, чтобы избежать добавления интерактивного ввода скрипта в историю.

  • История IPython. Он сохраняется в БД и автоматических переменных. Он содержит полные входы (readline захватывает каждую <Enter> строку отдельно для многострочных) и выходы. Сохранение реализовано в HistoryManager.store_inputs() (для входов) и HistoryManager.store_output() (для выходов), которые вызываются из InteractiveShell.run_cell и управляются его аргументом store_history. Последний, в свою очередь, вызывается из TerminalInteractiveShell.interact с помощью store_history=True.

Есть два способа решить проблему для любого слоя:

  • предотвратить добавление ввода в первую очередь. Этого нельзя сделать с помощью магии, предшествующей команде, только с помощью команды, которая запускается как отдельная команда и переключает флаг. Это потому, что, как вы видели, текущий ввод уже был сохранен к тому времени, когда магическая команда получает управление.

    • readline: there's no relevant entry in the public API, so it's implementation-specific. E.g. for pyreadline, adding is done with pyreadline.modes.basemode.BaseMode.add_history(). The mode object is accessible as get_ipython().readline.rl.mode.
    • Украшаем run_cell и add_history обертками, проверяющими флаги в соответствующих объектах, и пользовательской магической командой то, что устанавливает/переключает их, должно помочь.
  • автоматически удалять ввод/вывод evidence из истории сразу после выполнения. Это можно сделать с помощью префиксной магии.

    • IPython: HistoryManager doesn't have any facilities to remove entries (neither from DB nor from variables). Alas, hacking the DB by hand/replacing stock HistoryManager is necessary. Also note that the class has an optional cache of HistoryManager.db_cache_size (disabled by default).
    • readline: remove_history_item(index) находится в API. Вам нужно знать количество строк во входных данных.

В качестве альтернативы, если это требуется только для ввода паролей, рассмотрите другие способы, которые не отображают пароль на экране (то есть не делают его частью истории консоли):

  • getpass.getpass()
  • хранить его в другом месте (например, файл конфигурации, доступный только для чтения вами)
person ivan_pozdeev    schedule 30.01.2016
comment
1. предотвратить добавление ввода в первую очередь. Этого нельзя сделать с помощью волшебного префикса перед командой, только с той, которая запускается как отдельная команда и переключает флаг. Что является примером отдельной команды, переключающей флаг, чтобы предотвратить добавление ввода? 2. Декорирование run_cell и add_history обертками, проверяющими флаги в соответствующих объектах, и специальной магической командой, которая устанавливает/переключает их, должно помочь. Можете ли вы добавить пример? - person ShreevatsaR; 21.11.2016
comment
@ShreevatsaR 0) см. примечание об устаревании; 1)%toggle,your_command,%toggle; 2) это означает заменить эти функции обертками вокруг них; пример выходит за рамки ответа, это должно быть понятно любому, у кого есть приличный опыт. - person ivan_pozdeev; 22.11.2016

Я думаю, что наконец-то понял это. Этот метод на самом деле не «предотвращает» ipython для записи истории, а фактически удаляет запись истории. Но я все же думаю, что это хороший способ достичь этой цели.

История ipython хранится в файле базы данных sqlite в $(ipython locate)/profile_default/history.sqlite.

Таблица базы данных History состоит из четырех столбцов: session, line, source и source_raw. . Столбец session представляет session_id текущего сеанса, его можно получить с помощью метода в ipython: get_ipython().history_manager.hisdb.get_last_session_id() в ipython. Столбец line — это просто номер строки.

Итак, что я собираюсь сделать, так это удалить эту запись в базе данных в среде ipython:

1) Объект базы данных истории можно получить с помощью get_ipython().history_manager.db в ipython

hismgr = get_ipython().history_manager   

2) получить идентификатор сеанса:

session_id = hismgr.get_last_session_id()

3) удалить строку истории с line_id (предположим, здесь 111) и session_id

hismgr.db.execute('DELETE FROM history WHERE line={0} and session={1}'.format(111, session_id))

4) список массивов In и Out также похож на историю, но хранится в памяти, поэтому его можно очистить или перезаписать как переменную.

In[111]=Out[111]=''

«Предотвратить сохранение команды в истории ipython» означает удалить запись строки history в базе данных и перезаписать массив In и Out в среда ipython. И мы могли бы объединить эти четыре линии в одну, чтобы выполнить работу один раз за всех. Вот пример, если мы хотим удалить строку 128:

In [127]: history -l 3 -n
 124: history -l 3 -n
 125: hismgr = get_ipython().history_manager; session_id = hismgr.get_last_session_id();hismgr.db.execute('DELETE FROM history WHERE line={0} and session={1}'.format(123, session_id))
 126: history -l 3 -n

In [128]: passwd='123456'

In [129]: hismgr = get_ipython().history_manager; session_id = hismgr.get_last_session_id();hismgr.db.execute('DELETE FROM history WHERE line={0} and session={1}'.format(128, session_id));In[128]=Out[128]='';
Out[129]: <sqlite3.Cursor at 0x7f8dce3dae30>

In [130]: history -l 3 -n
 126: history -l 3 -n
 127: history -l 3 -n
 129: hismgr = get_ipython().history_manager; session_id = hismgr.get_last_session_id();hismgr.db.execute('DELETE FROM history WHERE line={0} and session={1}'.format(128, session_id));In[128]=Out[128]='';

Строка истории 128 исчезла.

Вот некоторые документы, которые я просмотрел

IPython.core.history.HistoryManager

python-sqlite3

person Evan    schedule 29.01.2016
comment
На самом деле это не предотвращает сохранение строки в истории, а удаляет ее из истории постфактум. - person ivan_pozdeev; 30.01.2016
comment
@ivan_pozdeev Я знаю. Но я прочитал документ ipython и не могу найти способ действительно предотвратить сохранение команды в истории, поэтому я пришел к выводу, что если я удалю строку, она будет выполнять ту же работу. - person Evan; 30.01.2016

Я сам искал решение, а потом понял, что могу просто input раскрыть секрет. Например, я использовал приведенное ниже для инициализации API github при использовании pygithub:

In [1]: gh = github.Github(base_url="https://api.github.com", login_or_token=input("token: "))
token: abcd

In [2]: %hist
gh = github.Github(base_url="https://api.github.com", login_or_token=input("token: "))
%hist
person haridsv    schedule 24.07.2021