Skip to content

Conversation

@anselor
Copy link
Contributor

@anselor anselor commented Apr 18, 2018

This PR addresses most of the feature described in #349 and adds examples and unit tests exercising the new features.
In a future round of changes, cmd2 will be updated to automatically use AutoCompleter for completion on all argparse-driven commands (unless overridden with a custom completion function)

anselor and others added 28 commits April 12, 2018 13:50
  - Fixed a few bugs in AutoCompleter dealing with nargs='+' or nargs='*'
  - Adjusted some help output dealing with narg ranges
  - Fixed spacing problem with printing argument help
* examples/tab_autocompletion.py
  - Removed debug code.
  - Minor changes.
This is to support installation from package managers on older OSes such as Debian 9.
Added more type hinting to AutoCompleter.
…ed function arguments.

Added example for fully custom completion functions mixed with argparse/AutoCompleter handling
 - Also demonstrates the ability to pass in a list, tuple, or dict of parameters to append to the custom completion function.
Added new test cases exercising the custom completion function calls.
Added AutoCompleter and rl_utils to the coverage report.
… prompt. Re-enabled test cases that were failing due to there not being a terminal during unit tests.
Updated AutoCompleter (#349) to match new directory structure from
packaging effort.
…constructor parameters in a more concise/general way. May also resolve the weird Mac issue on Python 3.6
@anselor anselor requested a review from tleonhardt as a code owner April 18, 2018 17:23
@codecov
Copy link

codecov bot commented Apr 18, 2018

Codecov Report

Merging #362 into master will increase coverage by 1.9%.
The diff coverage is 91.47%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master     #362     +/-   ##
=========================================
+ Coverage   89.33%   91.24%   +1.9%     
=========================================
  Files           2        3      +1     
  Lines        1876     2273    +397     
=========================================
+ Hits         1676     2074    +398     
+ Misses        200      199      -1
Impacted Files Coverage Δ
cmd2/rl_utils.py 100% <100%> (ø)
cmd2/cmd2.py 91.26% <100%> (+1.93%) ⬆️
cmd2/argparse_completer.py 90.65% <90.65%> (ø)
cmd2/__init__.py

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 7560b0a...df09c85. Read the comment docs.

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.

Overall a fabulous PR. I love the new feature.

Address my review comments and I'll take a quick look at it again after you do.

main.py Outdated

# Set "use_ipython" to True to include the ipy command if IPython is installed, which supports advanced interactive
# debugging of your application via introspection on self.
app = Cmd(use_ipython=False)
Copy link
Member

Choose a reason for hiding this comment

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

As long as no unit tests rely on this, then I would recommend setting use_ipython to True because that can aid debugging.

These are primarily tests related to readline completer functions which handle tab-completion of cmd2/cmd commands,
file system paths, and shell commands.

Copyright 2017 Todd Leonhardt <todd.leonhardt@gmail.com>
Copy link
Member

Choose a reason for hiding this comment

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

You should probably make this Copyright 2018 and yourself ;-)
This comment applies in multiple places.

@@ -0,0 +1,796 @@
# coding=utf-8
Copy link
Member

@tleonhardt tleonhardt Apr 18, 2018

Choose a reason for hiding this comment

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

In general module file names within Python packages are named using "snake_case" like auto_completer.py

[run]
# Source
source = cmd2.py
source = cmd2/
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for fixing the code coverage analysis configuration now that cmd2 is a multi-file package

import argparse
import re as _re
import sys
from argparse import OPTIONAL, ZERO_OR_MORE, ONE_OR_MORE, REMAINDER, PARSER, ArgumentError, _
Copy link
Member

Choose a reason for hiding this comment

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

I'm assuming the _ at the end of the line is a mistake and should be deleted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope, they have some sort of function called '_' that they use. I had to import it to override their behavior. Bizarre.

Copy link
Member

@tleonhardt tleonhardt Apr 19, 2018

Choose a reason for hiding this comment

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

Huh ... Well ain't that special ;-) They win the prize for the single worst function name I have ever seen!!!

Maybe add a comment?

import re as _re
import sys
from argparse import OPTIONAL, ZERO_OR_MORE, ONE_OR_MORE, REMAINDER, PARSER, ArgumentError, _
from .rl_utils import rl_force_redisplay
Copy link
Member

Choose a reason for hiding this comment

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

In general I try to order imports like so:
1st: built-in Python modules
2nd: 3rd-party modules
3rd: Our code
(and each section is alphabetical within that).

So recommend moving import from .rl_utils to end.

cmd2/rl_utils.py Outdated
pass


# Check what implementation of readline we are using
Copy link
Member

Choose a reason for hiding this comment

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

Convert comment before class to docstring after

pyparsing
pyperclip
wcwidth
colorama
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for adding this. We need to keep this up-to-date so that the documentation builds correctly on ReadTheDocs

first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
assert first_match is not None and \
cmd2_app.completion_matches == ['S01E02', 'S01E03', 'S02E01', 'S02E03']

Copy link
Member

Choose a reason for hiding this comment

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

Probably don't need quite this many trailing newlines at end of file

wcwidth
commands =
py.test {posargs: -n 2} --cov=cmd2 --cov-report=term-missing --forked
py.test {posargs: -n 2} --cov --cov-report=term-missing --forked
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for fixing these

def _query_movie_user_library(self):
return TabCompleteExample.USER_MOVIE_LIBRARY

def _filter_library(self, text, line, begidx, endidx, full, exclude=[]):
Copy link
Member

Choose a reason for hiding this comment

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

WARNING: Mutable default arguments in Python behave like static local variables in C - they are forever persistent and if you change the value within the function, you have permanently altered the default for the next time you call the function.

If this is how you intend this function to work, then please document to make it clear.

If this is NOT how you intend this function to work, then use a non-mutable default argument. If a tuple can work for you then that is fine. If you really need that argument to be a list then you can default it to None and then immediately first thing within the function check if it is None and if so assign an empty list to it.

tleonhardt
tleonhardt previously approved these changes Apr 19, 2018
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.

Everything looks good to me. Do you know if Kevin plans on reviewing?

@@ -0,0 +1,821 @@
# coding=utf-8
"""
AutoCompleter interprets the argparse.ArgumentParser internals to automatically
Copy link
Member

Choose a reason for hiding this comment

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

Changes all look good to me.

…ng unit tests due to the lack of a real terminal. Some more comments.
@anselor
Copy link
Contributor Author

anselor commented Apr 19, 2018

No idea if anyone else plans on reviewing this.

if not sys.stdout.isatty():
return

if rl_type == RlType.GNU: # pragma: no cover
Copy link
Member

Choose a reason for hiding this comment

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

This is covered on macOS when the gnureadline module is installed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason I blocked this out is because it can't be covered by the automated tests because there's isn't a terminal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess it depends on where we care about seeing the coverage.

Copy link
Member

Choose a reason for hiding this comment

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

Oh good point. I think it is reasonable to block it out if we know it won't be hit by any of our CI systems.

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.

Consider removing the "no cover" pragma from the one line which should be covered by our AppVeyor builds.

display_fixed = ctypes.c_int.in_dll(readline_lib, "rl_display_fixed")
display_fixed.value = 1

elif rl_type == RlType.PYREADLINE: # pragma: no cover
Copy link
Member

Choose a reason for hiding this comment

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

This is covered on Windows when the pyreadline module is installed, which is a conditional dependency on Windows so it should be. So this should be covered by our AppVeyor CI builds.

@tleonhardt
Copy link
Member

@kmvanbrunt I'm good to merge this in whenever. Let me know if you would like to review it or if we should just merge it in.

@tleonhardt tleonhardt merged commit 49a3290 into master Apr 19, 2018
@tleonhardt tleonhardt deleted the autocompleter branch April 19, 2018 21:21
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.

4 participants