Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add and document argcomplete.warn()

  • Loading branch information...
commit 48ea5060614f7a46197b5a2cc560c8b23d0bf7a8 1 parent 3d9b99a
@kislyuk authored
Showing with 55 additions and 34 deletions.
  1. +14 −0 README.rst
  2. +41 −34 argcomplete/__init__.py
View
14 README.rst
@@ -152,6 +152,20 @@ completions like you would get in the IPython shell:
import IPython
parser.add_argument("--python-name").completer = IPython.core.completer.Completer()
+Printing warnings in completers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Normal stdout/stderr output is suspended when argcomplete runs. Sometimes, though, when the user presses `<TAB>`, it's
+appropriate to print information about why completions generation failed. To do this, use `warn`:
+
+.. code-block:: python
+
+ from argcomplete import warn
+
+ def AwesomeWebServiceCompleter(prefix, **kwargs):
+ if login_failed:
+ warn("Please log in to Awesome Web Service to use autocompletion")
+ return completions
+
Global completion
-----------------
In global completion mode, you don't have to register each argcomplete-capable executable separately. Instead, bash
View
75 argcomplete/__init__.py
@@ -4,21 +4,25 @@
from __future__ import print_function
import os, sys, argparse, shlex, contextlib, subprocess, locale, re
-from . import completers
-from .my_argparse import IntrospectiveArgumentParser
try:
basestring
except NameError:
basestring = str
-if '_ARC_DEBUG' in os.environ:
- try:
- debug_stream = os.fdopen(9, 'w')
- except:
- debug_stream = sys.stderr
-else:
- debug_stream = open(os.devnull, 'w')
+_DEBUG = True if '_ARC_DEBUG' in os.environ else False
+
+try:
+ debug_stream = os.fdopen(9, 'w')
+except:
+ debug_stream = sys.stderr
+
+def warn(*args):
+ print("\n", file=debug_stream, *args)
+
+def debug(*args):
+ if _DEBUG:
+ print(file=debug_stream, *args)
BASH_FILE_COMPLETION_FALLBACK = 79
BASH_DIR_COMPLETION_FALLBACK = 80
@@ -31,6 +35,9 @@
argparse._AppendConstAction,
argparse._CountAction)
+from . import completers
+from .my_argparse import IntrospectiveArgumentParser
+
@contextlib.contextmanager
def mute_stdout():
stdout = sys.stdout
@@ -70,7 +77,7 @@ def split_word(word):
if isinstance(lexer.state, basestring) and lexer.state in lexer.whitespace:
point_in_word += 1
if point_in_word > len(word):
- print("In trailing whitespace", file=debug_stream)
+ debug("In trailing whitespace")
words.append(word)
word = ''
prefix, suffix = word[:point_in_word], word[point_in_word:]
@@ -82,11 +89,11 @@ def split_word(word):
if word == lexer.eof:
raise ArgcompleteException("Unexpected end of input")
if lexer.instream.tell() >= point:
- print("word", word, "split", file=debug_stream)
+ debug("word", word, "split")
return split_word(word)
words.append(word)
except ValueError:
- print("word", lexer.token, "split (lexer stopped)", file=debug_stream)
+ debug("word", lexer.token, "split (lexer stopped)")
if lexer.instream.tell() >= point:
return split_word(lexer.token)
else:
@@ -116,7 +123,7 @@ def autocomplete(argument_parser, always_complete_options=True, exit_method=os._
try:
output_stream = os.fdopen(8, 'wb')
except:
- print("Unable to open fd 8 for writing, quitting", file=debug_stream)
+ debug("Unable to open fd 8 for writing, quitting")
exit_method(1)
# print >>debug_stream, ""
@@ -125,7 +132,7 @@ def autocomplete(argument_parser, always_complete_options=True, exit_method=os._
ifs = os.environ.get('_ARGCOMPLETE_IFS', '\013')
if len(ifs) != 1:
- print("Invalid value for IFS, quitting".format(v=ifs), file=debug_stream)
+ debug("Invalid value for IFS, quitting".format(v=ifs))
exit_method(1)
comp_line = os.environ['COMP_LINE']
@@ -134,7 +141,7 @@ def autocomplete(argument_parser, always_complete_options=True, exit_method=os._
cword_prefix, cword_suffix, comp_words = split_line(comp_line, comp_point)
if os.environ['_ARGCOMPLETE'] == "2": # Hook recognized the first word as the interpreter
comp_words.pop(0)
- print("\nPREFIX: '{p}'".format(p=cword_prefix), "\nSUFFIX: '{s}'".format(s=cword_suffix), "\nWORDS:", comp_words, file=debug_stream)
+ debug("\nPREFIX: '{p}'".format(p=cword_prefix), "\nSUFFIX: '{s}'".format(s=cword_suffix), "\nWORDS:", comp_words)
active_parsers = [argument_parser]
parsed_args = argparse.Namespace()
@@ -152,15 +159,15 @@ def patchArgumentParser(parser):
# TODO: accomplish this with super
class IntrospectAction(action.__class__):
def __call__(self, parser, namespace, values, option_string=None):
- print('Action stub called on', self, file=debug_stream)
- print('\targs:', parser, namespace, values, option_string, file=debug_stream)
- print('\torig class:', self._orig_class, file=debug_stream)
- print('\torig callable:', self._orig_callable, file=debug_stream)
+ debug('Action stub called on', self)
+ debug('\targs:', parser, namespace, values, option_string)
+ debug('\torig class:', self._orig_class)
+ debug('\torig callable:', self._orig_callable)
visited_actions.append(self)
if self._orig_class == argparse._SubParsersAction:
- print('orig class is a subparsers action: patching and running it', file=debug_stream)
+ debug('orig class is a subparsers action: patching and running it')
active_subparser = self._name_parser_map[values[0]]
patchArgumentParser(active_subparser)
active_parsers.append(active_subparser)
@@ -176,23 +183,23 @@ def __call__(self, parser, namespace, values, option_string=None):
patchArgumentParser(argument_parser)
try:
- print("invoking parser with", comp_words[1:], file=debug_stream)
+ debug("invoking parser with", comp_words[1:])
with mute_stderr():
a = argument_parser.parse_known_args(comp_words[1:], namespace=parsed_args)
- print("parsed args:", a, file=debug_stream)
+ debug("parsed args:", a)
except BaseException as e:
- print("\nexception", type(e), str(e), "while parsing args", file=debug_stream)
+ debug("\nexception", type(e), str(e), "while parsing args")
- print("Active parsers:", active_parsers, file=debug_stream)
- print("Visited actions:", visited_actions, file=debug_stream)
- print("Parse result namespace:", parsed_args, file=debug_stream)
+ debug("Active parsers:", active_parsers)
+ debug("Visited actions:", visited_actions)
+ debug("Parse result namespace:", parsed_args)
completions = []
# Subcommand and options completion
for parser in active_parsers:
- print("Examining parser", parser, file=debug_stream)
+ debug("Examining parser", parser)
for action in parser._actions:
- print("Examining action", action, file=debug_stream)
+ debug("Examining action", action)
if isinstance(action, argparse._SubParsersAction):
subparser_activated = False
for subparser in action._name_parser_map.values():
@@ -206,10 +213,10 @@ def __call__(self, parser, namespace, values, option_string=None):
elif always_complete_options or (len(cword_prefix) > 0 and cword_prefix[0] in parser.prefix_chars):
completions += [option for option in action.option_strings if option.startswith(cword_prefix)]
- print("Active actions (L={l}): {a}".format(l=len(parser.active_actions), a=parser.active_actions), file=debug_stream)
+ debug("Active actions (L={l}): {a}".format(l=len(parser.active_actions), a=parser.active_actions))
for active_action in parser.active_actions:
- print("Activating completion for", active_action, active_action._orig_class, file=debug_stream)
+ debug("Activating completion for", active_action, active_action._orig_class)
#completer = getattr(active_action, 'completer', DefaultCompleter())
completer = getattr(active_action, 'completer', None)
@@ -229,16 +236,16 @@ def __call__(self, parser, namespace, values, option_string=None):
parsed_args=parsed_args) if c.startswith(cword_prefix)]
except TypeError:
# If completer is not callable, try the readline completion protocol instead
- print("Could not call completer, trying readline protocol instead", file=debug_stream)
+ debug("Could not call completer, trying readline protocol instead")
for i in range(9999):
next_completion = completer.complete(cword_prefix, i)
if next_completion is None:
break
if next_completion.startswith(cword_prefix):
completions.append(next_completion)
- print("Completions:", completions, file=debug_stream)
+ debug("Completions:", completions)
elif not isinstance(active_action, argparse._SubParsersAction):
- print("Completer not available, falling back", file=debug_stream)
+ debug("Completer not available, falling back")
try:
# TODO: what happens if completions contain newlines? How do I make compgen use IFS?
completions += subprocess.check_output(['bash', '-c', "compgen -A file -- '{p}'".format(p=cword_prefix)]).decode().splitlines()
@@ -267,7 +274,7 @@ def __call__(self, parser, namespace, values, option_string=None):
# print ifs.join([pipes.quote(c) for c in completions])
# print ifs.join([escape_completion_name_str(c) for c in completions])
- print("\nReturning completions:", completions, file=debug_stream)
+ debug("\nReturning completions:", completions)
output_stream.write(ifs.join(completions).encode(locale.getpreferredencoding()))
output_stream.flush()
# os.fsync(output_stream.fileno()) - this raises an error, why?
Please sign in to comment.
Something went wrong with that request. Please try again.