Skip to content

Conversation

@kotfu
Copy link
Member

@kotfu kotfu commented May 25, 2019

Fixes #669.

We have a readline history and a native in-memory history. Previous to this PR, only readline history was persistent between invocations of a cmd2 based app. Now both readline and native history are persistent. Plaintext history files are ignored, and do not cause read errors. All new history files written after this PR sill be in binary pickle format.

This includes several breaking changes noted in the changelog, including:

  • Change persistent history format to pickle instead of plain text
  • refactoring HistoryItem to not subclass string (it wouldn't unpickle)

@codecov
Copy link

codecov bot commented May 25, 2019

Codecov Report

Merging #689 into master will increase coverage by 0.16%.
The diff coverage is 99.07%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #689      +/-   ##
==========================================
+ Coverage   95.29%   95.46%   +0.16%     
==========================================
  Files          11       11              
  Lines        3191     3241      +50     
==========================================
+ Hits         3041     3094      +53     
+ Misses        150      147       -3
Impacted Files Coverage Δ
cmd2/history.py 100% <100%> (ø) ⬆️
cmd2/cmd2.py 95.64% <98.27%> (+0.06%) ⬆️
cmd2/argparse_completer.py 90.26% <0%> (+0.56%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d0add87...976ddc8. Read the comment docs.

tleonhardt
tleonhardt previously approved these changes May 25, 2019
@tleonhardt
Copy link
Member

Changes look good. I haven't had a chance to manually test yet, but plan to do so soon.

If we could get test coverage up of new code that would be a good thing.

python 3.4 pathlib doesn’t have .expanduser()
tleonhardt
tleonhardt previously approved these changes May 25, 2019
tleonhardt
tleonhardt previously approved these changes May 25, 2019
Copy link
Member

@tleonhardt tleonhardt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some manual testing and everything works well and as expected. I think we have an important missing feature and some minor documentation updates that need to be done. My view of remaining work is in the TODO below.

TODO:

  • Add a -a/--all flag to the history command and make the history command only show history from the current session by default, but the complete history when the -a flag is given
  • An alternative would be to add a boolean parameter to cmd2.Cmd.__init__ which determines whether or not the cmd2 history gets populated based on the persistent_history_file (but readline history would always be populated)
  • Minor doc update of cmd2.Cmd.__init__() docstring for persistent history parameters
  • Minor doc update of Searchable Command History section of Sphinx docs

@tleonhardt tleonhardt added this to the 0.9.13 milestone May 26, 2019
I found that at least with certain versions of Python and OSes, if I had a previous text-based readline history, an unhandled UnpicklingError exception could occur.  So now we catch that and several other possible errors which can theoretically occur during unpickling and just move on with an empty history.  The old file will get overwritten with one in the new format when the application exits.
… including those persisted from previous sessions

Also:
- History class has been modified to keep track of the session start index
- History class span(), str_search(), and regex_search() methods now take an optional 2nd boolean parameter `include_persisted` which determines whether or not commands persisted from previous sessions should be included by default
    - If a start index is manually specified, then it automatically includes the full search
- Updates unit tests
@tleonhardt
Copy link
Member

tleonhardt commented May 27, 2019

@kotfu and/or @kmvanbrunt
Please review the changes I made for designing and implementing the new -a/--all flag for the history command which enables display of all commands including those persisted from previous sessions (which are not displayed by default).

The History class now keeps track of the starting index for the current session and the span(), str_search(), and regex_search() methods all take an optional include_persisted boolean argument which specifies whether or history persisted from previous sessions should be included. If a starting index is specified in the argument to the span() method, then the value of include_persisted is ignored and the user gets what they ask for since they are being specific.

I also added some more exceptions to catch when attempting to unpickle a persistent history file to deal with some errors I found when a pre-existing readline text file existed.

@codecov
Copy link

codecov bot commented Jun 5, 2019

Codecov Report

Merging #689 into master will increase coverage by 0.16%.
The diff coverage is 99.07%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #689      +/-   ##
==========================================
+ Coverage   95.29%   95.46%   +0.16%     
==========================================
  Files          11       11              
  Lines        3191     3241      +50     
==========================================
+ Hits         3041     3094      +53     
+ Misses        150      147       -3
Impacted Files Coverage Δ
cmd2/history.py 100% <100%> (ø) ⬆️
cmd2/cmd2.py 95.64% <98.27%> (+0.06%) ⬆️
cmd2/argparse_completer.py 90.26% <0%> (+0.56%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d0add87...976ddc8. Read the comment docs.

1 similar comment
@codecov
Copy link

codecov bot commented Jun 5, 2019

Codecov Report

Merging #689 into master will increase coverage by 0.16%.
The diff coverage is 99.07%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #689      +/-   ##
==========================================
+ Coverage   95.29%   95.46%   +0.16%     
==========================================
  Files          11       11              
  Lines        3191     3241      +50     
==========================================
+ Hits         3041     3094      +53     
+ Misses        150      147       -3
Impacted Files Coverage Δ
cmd2/history.py 100% <100%> (ø) ⬆️
cmd2/cmd2.py 95.64% <98.27%> (+0.06%) ⬆️
cmd2/argparse_completer.py 90.26% <0%> (+0.56%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d0add87...976ddc8. Read the comment docs.

@codecov
Copy link

codecov bot commented Jun 5, 2019

Codecov Report

Merging #689 into master will increase coverage by 0.16%.
The diff coverage is 99.08%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #689      +/-   ##
==========================================
+ Coverage   95.29%   95.46%   +0.16%     
==========================================
  Files          11       11              
  Lines        3191     3241      +50     
==========================================
+ Hits         3041     3094      +53     
+ Misses        150      147       -3
Impacted Files Coverage Δ
cmd2/history.py 100% <100%> (ø) ⬆️
cmd2/cmd2.py 95.64% <98.3%> (+0.06%) ⬆️
cmd2/argparse_completer.py 90.26% <0%> (+0.56%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d0add87...1be2e4b. Read the comment docs.

tleonhardt
tleonhardt previously approved these changes Jun 5, 2019

# cmd2 history file used in hello_cmd2.py
cmd2_history.txt
cmd2_history.dat
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe ignore both the old and new name just to be safe?

…t no longer is dependent on readline.

Made certain paths absolute since the CWD could change between usages.
# Clear command and readline history
self.history.clear()

if self.persistent_history_file:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recent changes look fine

@tleonhardt tleonhardt merged commit 432427b into master Jun 6, 2019
@tleonhardt tleonhardt deleted the history_pickle branch June 6, 2019 18:37
@teto
Copy link

teto commented Jun 10, 2019

May I inquire why the change to binary fromat for something that is supposed to be human readable ? It's great to be able to just open an editor and look at the history or even to prefill an history.
sounds like a regression to me.

@teto
Copy link

teto commented Jun 10, 2019

why do we need 2 histories ? readline history and a native in-memory history..
Readline is a widely available dependency and this seems to add lots of complexity for both the user and the cmd2 developers ? I guess I am missing something xD

@tleonhardt
Copy link
Member

@teto The change to the format of the persistent history file is because we had a user request, #669, to persist the cmd2 history command history in addition to the readline history.

For this, the core cmd2 developers had a lively debate in regards to the if we should implement this and if so how we could do it in a way which was both convenient for end users and maintainable for core developers. In the end, we chose to do it using a single binary Pickle file from which we restore both the cmd2 history and readline history. I think most end users want persistent history and they don't care what format it gets persisted in and whether or not that is human readable.

In regards to why we want two histories, there are several reasons. First off cmd2 is a cross-platform framework which works the same way on Windows, macOS, and Linux. As a primarily Mac and Linux user I am quite familiar with and love readline history along with the +r and arrow-key capabilities built into it. However, few Windows users are familiar with readline and using it isn't very discoverable for them. A built-in history command on the other hand is very discoverable for all users. Secondly, the built-in cmd2 ** history** command has capabilities that go significantly beyond readline history, in part because it uses knowledge of internal cmd2 representations.

If your cmd2 development is negatively impacted by this change, can you please explain in detail precisely how and perhaps we can do something to help.

@teto
Copy link

teto commented Jun 10, 2019

I don't really mind the 2 histories. as a user, it mostly confuses me but that's fine. Hadn't thought of windows users I admit :/ I was just a bit surprised by the +563 −238 diff which makes me worried in terms of maintenance etc, I don't want cmd2 to become so complex that no new maintainer want to look at the code, it might the only program with 2 histories I know.

I think most end users want persistent history and they don't care what format it gets persisted in and whether or not that is human readable.

if people don't care what's the motivation for changing (btw I do care :p ) ? Any advantage of binary serialisation doesn't make sense for this usecase. Neither bash or zsh serialise the history. I like to have a look at it. What if I want to sync it on git ? I am not familiar with pickling but I fear it's not portable. What if the computer unexpectedly shuts down ? with zsh I can just open the history file and remove the last line to fix it but I don't think that will be possible with pickling.
My cmd2 commands are rather long and I rely on history a lot.

@teto
Copy link

teto commented Jun 10, 2019

Looking at the changelog, seems like the history items has grown to some big object, which would explain why one wouId want to use pickle. I will regret the txt based format but not enough to nag the nice maintainers :p thanks for your work.

@kotfu
Copy link
Member Author

kotfu commented Jun 10, 2019

A couple of thoughts about concerns raised by @teto.

  • History has always been a big (for this application) object; with this change we save the object instead of it disappearing when the app exits
  • picking works where python works, but is not portable to other tools
  • We have the same risk of data loss on unexpected shutdown that we did before we implemented this change. We have always accumulated the history in memory and only wrote it out on a clean exit.
  • There is a robust text-based interface to history via the built-in history command. You can save historical commands to a text file, search them, etc. It may meet many of your needs, but won't let you sync history with git.
  • If you want to persist history to a plain text file, you can use the python atexit module to register your own function which rips through the history array and writes it to the text file of your choosing

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider loading persistent_history_file into cmd2 history in addition to readline history

5 participants