argcomplete-1.8.1/0000755000076500000240000000000013040732051014634 5ustar kislyukstaff00000000000000argcomplete-1.8.1/argcomplete/0000755000076500000240000000000013040732051017136 5ustar kislyukstaff00000000000000argcomplete-1.8.1/argcomplete/__init__.py0000644000076500000240000007110113040207436021253 0ustar kislyukstaff00000000000000# Copyright 2012-2015, Andrey Kislyuk and argcomplete contributors. # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. from __future__ import absolute_import, division, print_function, unicode_literals import os, sys, argparse, contextlib from . import completers, my_shlex as shlex from .compat import USING_PYTHON2, str, sys_encoding, ensure_str, ensure_bytes from .completers import FilesCompleter from .my_argparse import IntrospectiveArgumentParser, action_is_satisfied, action_is_open, action_is_greedy _DEBUG = "_ARC_DEBUG" in os.environ debug_stream = sys.stderr def debug(*args): if _DEBUG: print(file=debug_stream, *args) BASH_FILE_COMPLETION_FALLBACK = 79 BASH_DIR_COMPLETION_FALLBACK = 80 safe_actions = (argparse._StoreAction, argparse._StoreConstAction, argparse._StoreTrueAction, argparse._StoreFalseAction, argparse._AppendAction, argparse._AppendConstAction, argparse._CountAction) @contextlib.contextmanager def mute_stdout(): stdout = sys.stdout sys.stdout = open(os.devnull, "w") try: yield finally: sys.stdout = stdout @contextlib.contextmanager def mute_stderr(): stderr = sys.stderr sys.stderr = open(os.devnull, "w") try: yield finally: sys.stderr.close() sys.stderr = stderr class ArgcompleteException(Exception): pass def split_line(line, point=None): if point is None: point = len(line) lexer = shlex.shlex(line, posix=True) lexer.whitespace_split = True lexer.wordbreaks = os.environ.get("_ARGCOMPLETE_COMP_WORDBREAKS", "") words = [] def split_word(word): # TODO: make this less ugly point_in_word = len(word) + point - lexer.instream.tell() if isinstance(lexer.state, (str, bytes)) and lexer.state in lexer.whitespace: point_in_word += 1 if point_in_word > len(word): debug("In trailing whitespace") words.append(word) word = "" prefix, suffix = word[:point_in_word], word[point_in_word:] prequote = "" # posix if lexer.state is not None and lexer.state in lexer.quotes: prequote = lexer.state # non-posix # if len(prefix) > 0 and prefix[0] in lexer.quotes: # prequote, prefix = prefix[0], prefix[1:] return prequote, prefix, suffix, words, lexer.last_wordbreak_pos while True: try: word = lexer.get_token() if word == lexer.eof: # TODO: check if this is ever unsafe # raise ArgcompleteException("Unexpected end of input") return "", "", "", words, None if lexer.instream.tell() >= point: debug("word", word, "split, lexer state: '{s}'".format(s=lexer.state)) return split_word(word) words.append(word) except ValueError: debug("word", lexer.token, "split (lexer stopped, state: '{s}')".format(s=lexer.state)) if lexer.instream.tell() >= point: return split_word(lexer.token) else: raise ArgcompleteException("Unexpected internal state. Please report this bug at https://github.com/kislyuk/argcomplete/issues.") # noqa def default_validator(completion, prefix): return completion.startswith(prefix) class CompletionFinder(object): """ Inherit from this class if you wish to override any of the stages below. Otherwise, use ``argcomplete.autocomplete()`` directly (it's a convenience instance of this class). It has the same signature as :meth:`CompletionFinder.__call__()`. """ def __init__(self, argument_parser=None, always_complete_options=True, exclude=None, validator=None, print_suppressed=False, default_completer=FilesCompleter(), append_space=None): self._parser = argument_parser self.always_complete_options = always_complete_options self.exclude = exclude if validator is None: validator = default_validator self.validator = validator self.print_suppressed = print_suppressed self.completing = False self._display_completions = {} self.default_completer = default_completer if append_space is None: append_space = os.environ.get("_ARGCOMPLETE_SUPPRESS_SPACE") != "1" self.append_space = append_space def __call__(self, argument_parser, always_complete_options=True, exit_method=os._exit, output_stream=None, exclude=None, validator=None, print_suppressed=False, append_space=None, default_completer=FilesCompleter()): """ :param argument_parser: The argument parser to autocomplete on :type argument_parser: :class:`argparse.ArgumentParser` :param always_complete_options: Controls the autocompletion of option strings if an option string opening character (normally ``-``) has not been entered. If ``True`` (default), both short (``-x``) and long (``--x``) option strings will be suggested. If ``False``, no option strings will be suggested. If ``long``, long options and short options with no long variant will be suggested. If ``short``, short options and long options with no short variant will be suggested. :type always_complete_options: boolean or string :param exit_method: Method used to stop the program after printing completions. Defaults to :meth:`os._exit`. If you want to perform a normal exit that calls exit handlers, use :meth:`sys.exit`. :type exit_method: callable :param exclude: List of strings representing options to be omitted from autocompletion :type exclude: iterable :param validator: Function to filter all completions through before returning (called with two string arguments, completion and prefix; return value is evaluated as a boolean) :type validator: callable :param print_suppressed: Whether or not to autocomplete options that have the ``help=argparse.SUPPRESS`` keyword argument set. :type print_suppressed: boolean :param append_space: Whether to append a space to unique matches. The default is ``True``. :type append_space: boolean .. note:: If you are not subclassing CompletionFinder to override its behaviors, use ``argcomplete.autocomplete()`` directly. It has the same signature as this method. Produces tab completions for ``argument_parser``. See module docs for more info. Argcomplete only executes actions if their class is known not to have side effects. Custom action classes can be added to argcomplete.safe_actions, if their values are wanted in the ``parsed_args`` completer argument, or their execution is otherwise desirable. """ self.__init__(argument_parser, always_complete_options=always_complete_options, exclude=exclude, validator=validator, print_suppressed=print_suppressed, append_space=append_space, default_completer=default_completer) if "_ARGCOMPLETE" not in os.environ: # not an argument completion invocation return global debug_stream try: debug_stream = os.fdopen(9, "w") except: debug_stream = sys.stderr if output_stream is None: try: output_stream = os.fdopen(8, "wb") except: debug("Unable to open fd 8 for writing, quitting") exit_method(1) # print("", stream=debug_stream) # for v in "COMP_CWORD COMP_LINE COMP_POINT COMP_TYPE COMP_KEY _ARGCOMPLETE_COMP_WORDBREAKS COMP_WORDS".split(): # print(v, os.environ[v], stream=debug_stream) ifs = os.environ.get("_ARGCOMPLETE_IFS", "\013") if len(ifs) != 1: debug("Invalid value for IFS, quitting [{v}]".format(v=ifs)) exit_method(1) comp_line = os.environ["COMP_LINE"] comp_point = int(os.environ["COMP_POINT"]) # Adjust comp_point for wide chars if USING_PYTHON2: comp_point = len(comp_line[:comp_point].decode(sys_encoding)) else: comp_point = len(comp_line.encode(sys_encoding)[:comp_point].decode(sys_encoding)) comp_line = ensure_str(comp_line) cword_prequote, cword_prefix, cword_suffix, comp_words, last_wordbreak_pos = split_line(comp_line, comp_point) if os.environ["_ARGCOMPLETE"] == "2": # Shell hook recognized the first word as the interpreter; discard it comp_words.pop(0) debug("\nLINE: '{l}'\nPREQUOTE: '{pq}'\nPREFIX: '{p}'".format(l=comp_line, pq=cword_prequote, p=cword_prefix), "\nSUFFIX: '{s}'".format(s=cword_suffix), "\nWORDS:", comp_words) completions = self._get_completions(comp_words, cword_prefix, cword_prequote, last_wordbreak_pos) debug("\nReturning completions:", completions) output_stream.write(ifs.join(completions).encode(sys_encoding)) output_stream.flush() debug_stream.flush() exit_method(0) def _get_completions(self, comp_words, cword_prefix, cword_prequote, last_wordbreak_pos): active_parsers = self._patch_argument_parser() parsed_args = argparse.Namespace() self.completing = True if USING_PYTHON2: # Python 2 argparse only properly works with byte strings. comp_words = [ensure_bytes(word) for word in comp_words] try: debug("invoking parser with", comp_words[1:]) with mute_stderr(): a = self._parser.parse_known_args(comp_words[1:], namespace=parsed_args) debug("parsed args:", a) except BaseException as e: debug("\nexception", type(e), str(e), "while parsing args") self.completing = False # key: complete word, value: description. completions = self.collect_completions(active_parsers, parsed_args, cword_prefix, debug) completions = self.filter_completions(completions) completions = self.quote_completions(completions, cword_prequote, last_wordbreak_pos) return completions def _patch_argument_parser(self): """ Since argparse doesn't support much introspection, we monkey-patch it to replace the parse_known_args method and all actions with hooks that tell us which action was last taken or about to be taken, and let us have the parser figure out which subparsers need to be activated (then recursively monkey-patch those). We save all active ArgumentParsers to extract all their possible option names later. """ self.active_parsers = [] self.visited_positionals = [] completer = self def patch(parser): completer.visited_positionals.append(parser) completer.active_parsers.append(parser) if isinstance(parser, IntrospectiveArgumentParser): return classname = "MonkeyPatchedIntrospectiveArgumentParser" if USING_PYTHON2: classname = bytes(classname) parser.__class__ = type(classname, (IntrospectiveArgumentParser, parser.__class__), {}) for action in parser._actions: if hasattr(action, "_orig_class"): continue # TODO: accomplish this with super class IntrospectAction(action.__class__): def __call__(self, parser, namespace, values, option_string=None): 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) if not completer.completing: self._orig_callable(parser, namespace, values, option_string=option_string) elif issubclass(self._orig_class, argparse._SubParsersAction): debug("orig class is a subparsers action: patching and running it") patch(self._name_parser_map[values[0]]) self._orig_callable(parser, namespace, values, option_string=option_string) elif self._orig_class in safe_actions: if not self.option_strings: completer.visited_positionals.append(self) self._orig_callable(parser, namespace, values, option_string=option_string) action._orig_class = action.__class__ action._orig_callable = action.__call__ action.__class__ = IntrospectAction patch(self._parser) debug("Active parsers:", self.active_parsers) debug("Visited positionals:", self.visited_positionals) return self.active_parsers def _get_subparser_completions(self, parser, cword_prefix): def filter_aliases(metavar, dest, prefix): if not metavar: return dest if dest and dest.startswith(prefix) else "" # metavar combines dest and aliases with ",". a = metavar.replace(",", "").split() return " ".join(x for x in a if x.startswith(prefix)) for action in parser._get_subactions(): subcmd_with_aliases = filter_aliases(action.metavar, action.dest, cword_prefix) if subcmd_with_aliases: self._display_completions[subcmd_with_aliases] = action.help completions = [subcmd for subcmd in parser.choices.keys() if subcmd.startswith(cword_prefix)] return completions def _include_options(self, action, cword_prefix): if len(cword_prefix) > 0 or self.always_complete_options is True: return [ensure_str(opt) for opt in action.option_strings if ensure_str(opt).startswith(cword_prefix)] long_opts = [ensure_str(opt) for opt in action.option_strings if len(opt) > 2] short_opts = [ensure_str(opt) for opt in action.option_strings if len(opt) <= 2] if self.always_complete_options == "long": return long_opts if long_opts else short_opts elif self.always_complete_options == "short": return short_opts if short_opts else long_opts return [] def _get_option_completions(self, parser, cword_prefix): self._display_completions.update( [[" ".join(ensure_str(x) for x in action.option_strings if ensure_str(x).startswith(cword_prefix)), action.help] # noqa for action in parser._actions if action.option_strings]) option_completions = [] for action in parser._actions: if action.help == argparse.SUPPRESS and not self.print_suppressed: continue if not self._action_allowed(action, parser): continue if not isinstance(action, argparse._SubParsersAction): option_completions += self._include_options(action, cword_prefix) return option_completions @staticmethod def _action_allowed(action, parser): # Logic adapted from take_action in ArgumentParser._parse_known_args # (members are saved by my_argparse.IntrospectiveArgumentParser) for conflict_action in parser._action_conflicts.get(action, []): if conflict_action in parser._seen_non_default_actions: return False return True def _complete_active_option(self, parser, next_positional, cword_prefix, parsed_args, completions): debug("Active actions (L={l}): {a}".format(l=len(parser.active_actions), a=parser.active_actions)) isoptional = cword_prefix and cword_prefix[0] in parser.prefix_chars greedy_actions = [x for x in parser.active_actions if action_is_greedy(x, isoptional)] if greedy_actions: assert len(greedy_actions) == 1, "expect at most 1 greedy action" # This means the action will fail to parse if the word under the cursor is not given # to it, so give it exclusive control over completions (flush previous completions) debug("Resetting completions because", greedy_actions[0], "must consume the next argument") self._display_completions = {} completions = [] elif isoptional: # Only run completers if current word does not start with - (is not an optional) return completions complete_remaining_positionals = False # Use the single greedy action (if there is one) or all active actions. for active_action in greedy_actions or parser.active_actions: if not active_action.option_strings: # action is a positional if action_is_open(active_action): # Any positional arguments after this may slide down into this action # if more arguments are added (since the user may not be done yet), # so it is extremely difficult to tell which completers to run. # Running all remaining completers will probably show more than the user wants # but it also guarantees we won't miss anything. complete_remaining_positionals = True if not complete_remaining_positionals: if action_is_satisfied(active_action) and not action_is_open(active_action): debug("Skipping", active_action) continue debug("Activating completion for", active_action, active_action._orig_class) # completer = getattr(active_action, "completer", DefaultCompleter()) completer = getattr(active_action, "completer", None) if completer is None: if active_action.choices is not None and not isinstance(active_action, argparse._SubParsersAction): completer = completers.ChoicesCompleter(active_action.choices) elif not isinstance(active_action, argparse._SubParsersAction): completer = self.default_completer if completer: if callable(completer): completions_from_callable = [c for c in completer( prefix=cword_prefix, action=active_action, parsed_args=parsed_args) if self.validator(c, cword_prefix)] if completions_from_callable: completions += completions_from_callable if isinstance(completer, completers.ChoicesCompleter): self._display_completions.update( [[x, active_action.help] for x in completions_from_callable]) else: self._display_completions.update( [[x, ""] for x in completions_from_callable]) else: debug("Completer is not callable, trying the readline completer protocol instead") for i in range(9999): next_completion = completer.complete(cword_prefix, i) if next_completion is None: break if self.validator(next_completion, cword_prefix): self._display_completions.update({next_completion: ""}) completions.append(next_completion) debug("Completions:", completions) return completions def collect_completions(self, active_parsers, parsed_args, cword_prefix, debug): """ Visits the active parsers and their actions, executes their completers or introspects them to collect their option strings. Returns the resulting completions as a list of strings. This method is exposed for overriding in subclasses; there is no need to use it directly. """ completions = [] debug("all active parsers:", active_parsers) active_parser = active_parsers[-1] debug("active_parser:", active_parser) if self.always_complete_options or (len(cword_prefix) > 0 and cword_prefix[0] in active_parser.prefix_chars): completions += self._get_option_completions(active_parser, cword_prefix) debug("optional options:", completions) next_positional = self._get_next_positional() debug("next_positional:", next_positional) if isinstance(next_positional, argparse._SubParsersAction): completions += self._get_subparser_completions(next_positional, cword_prefix) completions = self._complete_active_option(active_parser, next_positional, cword_prefix, parsed_args, completions) debug("active options:", completions) debug("display completions:", self._display_completions) return completions def _get_next_positional(self): """ Get the next positional action if it exists. """ active_parser = self.active_parsers[-1] last_positional = self.visited_positionals[-1] all_positionals = active_parser._get_positional_actions() if not all_positionals: return None if active_parser == last_positional: return all_positionals[0] i = 0 for i in range(len(all_positionals)): if all_positionals[i] == last_positional: break if i + 1 < len(all_positionals): return all_positionals[i + 1] return None def filter_completions(self, completions): """ Ensures collected completions are Unicode text, de-duplicates them, and excludes those specified by ``exclude``. Returns the filtered completions as an iterable. This method is exposed for overriding in subclasses; there is no need to use it directly. """ # On Python 2, we have to make sure all completions are unicode objects before we continue and output them. # Otherwise, because python disobeys the system locale encoding and uses ascii as the default encoding, it will # try to implicitly decode string objects using ascii, and fail. completions = [ensure_str(c) for c in completions] # De-duplicate completions and remove excluded ones if self.exclude is None: self.exclude = set() seen = set(self.exclude) return [c for c in completions if c not in seen and not seen.add(c)] def quote_completions(self, completions, cword_prequote, last_wordbreak_pos): """ If the word under the cursor started with a quote (as indicated by a nonempty ``cword_prequote``), escapes occurrences of that quote character in the completions, and adds the quote to the beginning of each completion. Otherwise, escapes all characters that bash splits words on (``COMP_WORDBREAKS``), and removes portions of completions before the first colon if (``COMP_WORDBREAKS``) contains a colon. If there is only one completion, and it doesn't end with a **continuation character** (``/``, ``:``, or ``=``), adds a space after the completion. This method is exposed for overriding in subclasses; there is no need to use it directly. """ special_chars = "\\" # If the word under the cursor was quoted, escape the quote char. # Otherwise, escape all special characters and specially handle all COMP_WORDBREAKS chars. if cword_prequote == "": # Bash mangles completions which contain characters in COMP_WORDBREAKS. # This workaround has the same effect as __ltrim_colon_completions in bash_completion # (extended to characters other than the colon). if last_wordbreak_pos: completions = [c[last_wordbreak_pos + 1:] for c in completions] special_chars += "();<>|&!`$* \t\n\"'" elif cword_prequote == '"': special_chars += '"`$!' if os.environ.get("_ARGCOMPLETE_SHELL") == "tcsh": # tcsh escapes special characters itself. special_chars = "" elif cword_prequote == "'": # Nothing can be escaped in single quotes, so we need to close # the string, escape the single quote, then open a new string. special_chars = "" completions = [c.replace("'", r"'\''") for c in completions] for char in special_chars: completions = [c.replace(char, "\\" + char) for c in completions] if self.append_space: # Similar functionality in bash was previously turned off by supplying the "-o nospace" option to complete. # Now it is conditionally disabled using "compopt -o nospace" if the match ends in a continuation character. # This code is retained for environments where this isn't done natively. continuation_chars = "=/:" if len(completions) == 1 and completions[0][-1] not in continuation_chars: if cword_prequote == "": completions[0] += " " return completions def rl_complete(self, text, state): """ Alternate entry point for using the argcomplete completer in a readline-based REPL. See also `rlcompleter `_. Usage: .. code-block:: python import argcomplete, argparse, readline parser = argparse.ArgumentParser() ... completer = argcomplete.CompletionFinder(parser) readline.set_completer_delims("") readline.set_completer(completer.rl_complete) readline.parse_and_bind("tab: complete") result = input("prompt> ") (Use ``raw_input`` instead of ``input`` on Python 2, or use `eight `_). """ if state == 0: cword_prequote, cword_prefix, cword_suffix, comp_words, first_colon_pos = split_line(text) comp_words.insert(0, sys.argv[0]) matches = self._get_completions(comp_words, cword_prefix, cword_prequote, first_colon_pos) self._rl_matches = [text + match[len(cword_prefix):] for match in matches] if state < len(self._rl_matches): return self._rl_matches[state] else: return None def get_display_completions(self): """ This function returns a mapping of option names to their help strings for displaying to the user Usage: .. code-block:: python def display_completions(substitution, matches, longest_match_length): _display_completions = argcomplete.autocomplete.get_display_completions() print("") if _display_completions: help_len = [len(x) for x in _display_completions.values() if x] if help_len: maxlen = max([len(x) for x in _display_completions]) print("\\n".join("{0:{2}} -- {1}".format(k, v, maxlen) for k, v in sorted(_display_completions.items()))) else: print(" ".join(k for k in sorted(_display_completions))) else: print(" ".join(x for x in sorted(matches))) import readline print("cli /> {0}".format(readline.get_line_buffer()), end="") readline.redisplay() ... readline.set_completion_display_matches_hook(display_completions) """ return self._display_completions class ExclusiveCompletionFinder(CompletionFinder): @staticmethod def _action_allowed(action, parser): if not CompletionFinder._action_allowed(action, parser): return False append_classes = (argparse._AppendAction, argparse._AppendConstAction) if action._orig_class in append_classes: return True if action not in parser._seen_non_default_actions: return True return False autocomplete = CompletionFinder() autocomplete.__doc__ = """ Use this to access argcomplete. See :meth:`argcomplete.CompletionFinder.__call__()`. """ def warn(*args): """ Prints **args** to standard error when running completions. This will interrupt the user's command line interaction; use it to indicate an error condition that is preventing your completer from working. """ print("\n", file=debug_stream, *args) argcomplete-1.8.1/argcomplete/bash_completion.d/0000755000076500000240000000000013040732051022526 5ustar kislyukstaff00000000000000argcomplete-1.8.1/argcomplete/bash_completion.d/python-argcomplete.sh0000644000076500000240000000447513040207436026721 0ustar kislyukstaff00000000000000# Copyright 2012-2013, Andrey Kislyuk and argcomplete contributors. # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. # Copy of __expand_tilde_by_ref from bash-completion __python_argcomplete_expand_tilde_by_ref () { if [ "${!1:0:1}" = "~" ]; then if [ "${!1}" != "${!1//\/}" ]; then eval $1="${!1/%\/*}"/'${!1#*/}'; else eval $1="${!1}"; fi; fi } _python_argcomplete_global() { local executable=$1 __python_argcomplete_expand_tilde_by_ref executable local ARGCOMPLETE=0 if [[ "$executable" == python* ]] || [[ "$executable" == pypy* ]]; then if [[ -f "${COMP_WORDS[1]}" ]] && (head -c 1024 "${COMP_WORDS[1]}" | grep --quiet "PYTHON_ARGCOMPLETE_OK") >/dev/null 2>&1; then local ARGCOMPLETE=2 else return fi elif which "$executable" >/dev/null 2>&1; then local SCRIPT_NAME=$(which "$executable") if (type -t pyenv && [[ "$SCRIPT_NAME" = $(pyenv root)/shims/* ]]) >/dev/null 2>&1; then local SCRIPT_NAME=$(pyenv which "$executable") fi if (head -c 1024 "$SCRIPT_NAME" | grep --quiet "PYTHON_ARGCOMPLETE_OK") >/dev/null 2>&1; then local ARGCOMPLETE=1 elif (head -c 1024 "$SCRIPT_NAME" | egrep --quiet "(PBR Generated)|(EASY-INSTALL-(SCRIPT|ENTRY-SCRIPT|DEV-SCRIPT))" \ && python-argcomplete-check-easy-install-script "$SCRIPT_NAME") >/dev/null 2>&1; then local ARGCOMPLETE=1 fi fi if [[ $ARGCOMPLETE == 1 ]] || [[ $ARGCOMPLETE == 2 ]]; then local IFS=$(echo -e '\v') COMPREPLY=( $(_ARGCOMPLETE_IFS="$IFS" \ COMP_LINE="$COMP_LINE" \ COMP_POINT="$COMP_POINT" \ COMP_TYPE="$COMP_TYPE" \ _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \ _ARGCOMPLETE=$ARGCOMPLETE \ _ARGCOMPLETE_SUPPRESS_SPACE=1 \ "$executable" "${COMP_WORDS[@]:1:ARGCOMPLETE-1}" 8>&1 9>&2 1>/dev/null 2>&1) ) if [[ $? != 0 ]]; then unset COMPREPLY elif [[ "$COMPREPLY" =~ [=/:]$ ]]; then compopt -o nospace fi else type -t _completion_loader | grep -q 'function' && _completion_loader "$@" fi } complete -o default -o bashdefault -D -F _python_argcomplete_global argcomplete-1.8.1/argcomplete/compat.py0000644000076500000240000000101412730011252020765 0ustar kislyukstaff00000000000000from __future__ import absolute_import, division, print_function, unicode_literals import locale import sys sys_encoding = locale.getpreferredencoding() USING_PYTHON2 = True if sys.version_info < (3, 0) else False if USING_PYTHON2: str = unicode # noqa else: str = str def ensure_bytes(x, encoding=sys_encoding): if not isinstance(x, bytes): x = x.encode(encoding) return x def ensure_str(x, encoding=sys_encoding): if not isinstance(x, str): x = x.decode(encoding) return x argcomplete-1.8.1/argcomplete/completers.py0000644000076500000240000000664712730011252021700 0ustar kislyukstaff00000000000000# Copyright 2012-2013, Andrey Kislyuk and argcomplete contributors. # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. from __future__ import absolute_import, division, print_function, unicode_literals import os import subprocess from .compat import str, sys_encoding def _call(*args, **kwargs): try: return subprocess.check_output(*args, **kwargs).decode(sys_encoding).splitlines() except subprocess.CalledProcessError: return [] class ChoicesCompleter(object): def __init__(self, choices): self.choices = [] for choice in choices: if isinstance(choice, bytes): choice = choice.decode(sys_encoding) if not isinstance(choice, str): choice = str(choice) self.choices.append(choice) def __call__(self, prefix, **kwargs): return (c for c in self.choices if c.startswith(prefix)) def EnvironCompleter(prefix, **kwargs): return (v for v in os.environ if v.startswith(prefix)) class FilesCompleter(object): """ File completer class, optionally takes a list of allowed extensions """ def __init__(self, allowednames=(), directories=True): # Fix if someone passes in a string instead of a list if isinstance(allowednames, (str, bytes)): allowednames = [allowednames] self.allowednames = [x.lstrip("*").lstrip(".") for x in allowednames] self.directories = directories def __call__(self, prefix, **kwargs): completion = [] if self.allowednames: if self.directories: files = _call(["bash", "-c", "compgen -A directory -- '{p}'".format(p=prefix)]) completion += [f + "/" for f in files] for x in self.allowednames: completion += _call(["bash", "-c", "compgen -A file -X '!*.{0}' -- '{p}'".format(x, p=prefix)]) else: completion += _call(["bash", "-c", "compgen -A file -- '{p}'".format(p=prefix)]) anticomp = _call(["bash", "-c", "compgen -A directory -- '{p}'".format(p=prefix)]) completion = list(set(completion) - set(anticomp)) if self.directories: completion += [f + "/" for f in anticomp] return completion class _FilteredFilesCompleter(object): def __init__(self, predicate): """ Create the completer A predicate accepts as its only argument a candidate path and either accepts it or rejects it. """ assert predicate, "Expected a callable predicate" self.predicate = predicate def __call__(self, prefix, **kwargs): """ Provide completions on prefix """ target_dir = os.path.dirname(prefix) try: names = os.listdir(target_dir or ".") except: return # empty iterator incomplete_part = os.path.basename(prefix) # Iterate on target_dir entries and filter on given predicate for name in names: if not name.startswith(incomplete_part): continue candidate = os.path.join(target_dir, name) if not self.predicate(candidate): continue yield candidate + "/" if os.path.isdir(candidate) else candidate class DirectoriesCompleter(_FilteredFilesCompleter): def __init__(self): _FilteredFilesCompleter.__init__(self, predicate=os.path.isdir) argcomplete-1.8.1/argcomplete/my_argparse.py0000644000076500000240000003576713040207436022047 0ustar kislyukstaff00000000000000# Copyright 2012-2013, Andrey Kislyuk and argcomplete contributors. # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. from argparse import ArgumentParser, ArgumentError, SUPPRESS, _SubParsersAction from argparse import OPTIONAL, ZERO_OR_MORE, ONE_OR_MORE, REMAINDER, PARSER from argparse import _get_action_name, _ _num_consumed_args = {} def action_is_satisfied(action): ''' Returns False if the parse would raise an error if no more arguments are given to this action, True otherwise. ''' num_consumed_args = _num_consumed_args.get(action, 0) if action.nargs in [OPTIONAL, ZERO_OR_MORE, REMAINDER]: return True if action.nargs == ONE_OR_MORE: return num_consumed_args >= 1 if action.nargs == PARSER: # Not sure what this should be, but this previously always returned False # so at least this won't break anything that wasn't already broken. return False if action.nargs is None: return num_consumed_args == 1 assert isinstance(action.nargs, int), 'failed to handle a possible nargs value: %r' % action.nargs return num_consumed_args == action.nargs def action_is_open(action): ''' Returns True if action could consume more arguments (i.e., its pattern is open). ''' num_consumed_args = _num_consumed_args.get(action, 0) if action.nargs in [ZERO_OR_MORE, ONE_OR_MORE, PARSER, REMAINDER]: return True if action.nargs == OPTIONAL or action.nargs is None: return num_consumed_args == 0 assert isinstance(action.nargs, int), 'failed to handle a possible nargs value: %r' % action.nargs return num_consumed_args < action.nargs def action_is_greedy(action, isoptional=False): ''' Returns True if action will necessarily consume the next argument. isoptional indicates whether the argument is an optional (starts with -). ''' num_consumed_args = _num_consumed_args.get(action, 0) if action.option_strings: if not isoptional and not action_is_satisfied(action): return True return action.nargs == REMAINDER else: return action.nargs == REMAINDER and num_consumed_args >= 1 class IntrospectiveArgumentParser(ArgumentParser): ''' The following is a verbatim copy of ArgumentParser._parse_known_args (Python 2.7.3), except for the lines that contain the string "Added by argcomplete". ''' def _parse_known_args(self, arg_strings, namespace): _num_consumed_args.clear() # Added by argcomplete self._argcomplete_namespace = namespace self.active_actions = [] # Added by argcomplete # replace arg strings that are file references if self.fromfile_prefix_chars is not None: arg_strings = self._read_args_from_files(arg_strings) # map all mutually exclusive arguments to the other arguments # they can't occur with action_conflicts = {} self._action_conflicts = action_conflicts # Added by argcomplete for mutex_group in self._mutually_exclusive_groups: group_actions = mutex_group._group_actions for i, mutex_action in enumerate(mutex_group._group_actions): conflicts = action_conflicts.setdefault(mutex_action, []) conflicts.extend(group_actions[:i]) conflicts.extend(group_actions[i + 1:]) # find all option indices, and determine the arg_string_pattern # which has an 'O' if there is an option at an index, # an 'A' if there is an argument, or a '-' if there is a '--' option_string_indices = {} arg_string_pattern_parts = [] arg_strings_iter = iter(arg_strings) for i, arg_string in enumerate(arg_strings_iter): # all args after -- are non-options if arg_string == '--': arg_string_pattern_parts.append('-') for arg_string in arg_strings_iter: arg_string_pattern_parts.append('A') # otherwise, add the arg to the arg strings # and note the index if it was an option else: option_tuple = self._parse_optional(arg_string) if option_tuple is None: pattern = 'A' else: option_string_indices[i] = option_tuple pattern = 'O' arg_string_pattern_parts.append(pattern) # join the pieces together to form the pattern arg_strings_pattern = ''.join(arg_string_pattern_parts) # converts arg strings to the appropriate and then takes the action seen_actions = set() seen_non_default_actions = set() self._seen_non_default_actions = seen_non_default_actions # Added by argcomplete def take_action(action, argument_strings, option_string=None): seen_actions.add(action) argument_values = self._get_values(action, argument_strings) # error if this argument is not allowed with other previously # seen arguments, assuming that actions that use the default # value don't really count as "present" if argument_values is not action.default: seen_non_default_actions.add(action) for conflict_action in action_conflicts.get(action, []): if conflict_action in seen_non_default_actions: msg = _('not allowed with argument %s') action_name = _get_action_name(conflict_action) raise ArgumentError(action, msg % action_name) # take the action if we didn't receive a SUPPRESS value # (e.g. from a default) if argument_values is not SUPPRESS \ or isinstance(action, _SubParsersAction): try: action(self, namespace, argument_values, option_string) except: # Begin added by argcomplete # When a subparser action is taken and fails due to incomplete arguments, it does not merge the # contents of its parsed namespace into the parent namespace. Do that here to allow completers to # access the partially parsed arguments for the subparser. if isinstance(action, _SubParsersAction): subnamespace = action._name_parser_map[argument_values[0]]._argcomplete_namespace for key, value in vars(subnamespace).items(): setattr(namespace, key, value) # End added by argcomplete raise # function to convert arg_strings into an optional action def consume_optional(start_index): # get the optional identified at this index option_tuple = option_string_indices[start_index] action, option_string, explicit_arg = option_tuple # identify additional optionals in the same arg string # (e.g. -xyz is the same as -x -y -z if no args are required) match_argument = self._match_argument action_tuples = [] while True: # if we found no optional action, skip it if action is None: extras.append(arg_strings[start_index]) return start_index + 1 # if there is an explicit argument, try to match the # optional's string arguments to only this if explicit_arg is not None: arg_count = match_argument(action, 'A') # if the action is a single-dash option and takes no # arguments, try to parse more single-dash options out # of the tail of the option string chars = self.prefix_chars if arg_count == 0 and option_string[1] not in chars: action_tuples.append((action, [], option_string)) char = option_string[0] option_string = char + explicit_arg[0] new_explicit_arg = explicit_arg[1:] or None optionals_map = self._option_string_actions if option_string in optionals_map: action = optionals_map[option_string] explicit_arg = new_explicit_arg else: msg = _('ignored explicit argument %r') raise ArgumentError(action, msg % explicit_arg) # if the action expect exactly one argument, we've # successfully matched the option; exit the loop elif arg_count == 1: stop = start_index + 1 args = [explicit_arg] action_tuples.append((action, args, option_string)) break # error if a double-dash option did not use the # explicit argument else: msg = _('ignored explicit argument %r') raise ArgumentError(action, msg % explicit_arg) # if there is no explicit argument, try to match the # optional's string arguments with the following strings # if successful, exit the loop else: start = start_index + 1 selected_patterns = arg_strings_pattern[start:] self.active_actions = [action] # Added by argcomplete _num_consumed_args[action] = 0 # Added by argcomplete arg_count = match_argument(action, selected_patterns) stop = start + arg_count args = arg_strings[start:stop] # Begin added by argcomplete # If the pattern is not open (e.g. no + at the end), remove the action from active actions (since # it wouldn't be able to consume any more args) _num_consumed_args[action] = len(args) if not action_is_open(action): self.active_actions.remove(action) # End added by argcomplete action_tuples.append((action, args, option_string)) break # add the Optional to the list and return the index at which # the Optional's string args stopped assert action_tuples for action, args, option_string in action_tuples: take_action(action, args, option_string) return stop # the list of Positionals left to be parsed; this is modified # by consume_positionals() positionals = self._get_positional_actions() # function to convert arg_strings into positional actions def consume_positionals(start_index): # match as many Positionals as possible match_partial = self._match_arguments_partial selected_pattern = arg_strings_pattern[start_index:] arg_counts = match_partial(positionals, selected_pattern) # slice off the appropriate arg strings for each Positional # and add the Positional and its args to the list for action, arg_count in zip(positionals, arg_counts): # Added by argcomplete self.active_actions.append(action) # Added by argcomplete for action, arg_count in zip(positionals, arg_counts): args = arg_strings[start_index: start_index + arg_count] start_index += arg_count _num_consumed_args[action] = len(args) # Added by argcomplete take_action(action, args) # slice off the Positionals that we just parsed and return the # index at which the Positionals' string args stopped positionals[:] = positionals[len(arg_counts):] return start_index # consume Positionals and Optionals alternately, until we have # passed the last option string extras = [] start_index = 0 if option_string_indices: max_option_string_index = max(option_string_indices) else: max_option_string_index = -1 while start_index <= max_option_string_index: # consume any Positionals preceding the next option next_option_string_index = min([ index for index in option_string_indices if index >= start_index]) if start_index != next_option_string_index: positionals_end_index = consume_positionals(start_index) # only try to parse the next optional if we didn't consume # the option string during the positionals parsing if positionals_end_index > start_index: start_index = positionals_end_index continue else: start_index = positionals_end_index # if we consumed all the positionals we could and we're not # at the index of an option string, there were extra arguments if start_index not in option_string_indices: strings = arg_strings[start_index:next_option_string_index] extras.extend(strings) start_index = next_option_string_index # consume the next optional and any arguments for it start_index = consume_optional(start_index) # consume any positionals following the last Optional stop_index = consume_positionals(start_index) # if we didn't consume all the argument strings, there were extras extras.extend(arg_strings[stop_index:]) # if we didn't use all the Positional objects, there were too few # arg strings supplied. if positionals: self.active_actions.append(positionals[0]) # Added by argcomplete self.error(_('too few arguments')) # make sure all required actions were present for action in self._actions: if action.required: if action not in seen_actions: name = _get_action_name(action) self.error(_('argument %s is required') % name) # make sure all required groups had one option present for group in self._mutually_exclusive_groups: if group.required: for action in group._group_actions: if action in seen_non_default_actions: break # if no actions were used, report the error else: names = [_get_action_name(action) for action in group._group_actions if action.help is not SUPPRESS] msg = _('one of the arguments %s is required') self.error(msg % ' '.join(names)) # return the updated namespace and the extra arguments return namespace, extras argcomplete-1.8.1/argcomplete/my_shlex.py0000644000076500000240000003164213040731545021355 0ustar kislyukstaff00000000000000# -*- coding: utf-8 -*- # This copy of shlex.py from Python 3.6 is distributed with argcomplete. # It contains only the shlex class, with modifications as noted. """A lexical analyzer class for simple shell-like syntaxes.""" # Module and documentation by Eric S. Raymond, 21 Dec 1998 # Input stacking and error message cleanup added by ESR, March 2000 # push_source() and pop_source() made explicit by ESR, January 2001. # Posix compliance, split(), string arguments, and # iterator interface by Gustavo Niemeyer, April 2003. # changes to tokenize more like Posix shells by Vinay Sajip, July 2016. import os import sys from collections import deque # Modified by argcomplete: 2/3 compatibility # Note: cStringIO is not compatible with Unicode try: from StringIO import StringIO except ImportError: from io import StringIO # Modified by argcomplete: 2/3 compatibility try: basestring except NameError: basestring = str class shlex: "A lexical analyzer class for simple shell-like syntaxes." def __init__(self, instream=None, infile=None, posix=False, punctuation_chars=False): # Modified by argcomplete: 2/3 compatibility if isinstance(instream, basestring): instream = StringIO(instream) if instream is not None: self.instream = instream self.infile = infile else: self.instream = sys.stdin self.infile = None self.posix = posix if posix: self.eof = None else: self.eof = '' self.commenters = '#' self.wordchars = ('abcdfeghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_') # Modified by argcomplete: 2/3 compatibility # if self.posix: # self.wordchars += ('ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' # 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ') self.whitespace = ' \t\r\n' self.whitespace_split = False self.quotes = '\'"' self.escape = '\\' self.escapedquotes = '"' self.state = ' ' self.pushback = deque() self.lineno = 1 self.debug = 0 self.token = '' self.filestack = deque() self.source = None if not punctuation_chars: punctuation_chars = '' elif punctuation_chars is True: punctuation_chars = '();<>|&' self.punctuation_chars = punctuation_chars if punctuation_chars: # _pushback_chars is a push back queue used by lookahead logic self._pushback_chars = deque() # these chars added because allowed in file names, args, wildcards self.wordchars += '~-./*?=' #remove any punctuation chars from wordchars t = self.wordchars.maketrans(dict.fromkeys(punctuation_chars)) self.wordchars = self.wordchars.translate(t) # Modified by argcomplete: Record last wordbreak position self.last_wordbreak_pos = None self.wordbreaks = '' def push_token(self, tok): "Push a token onto the stack popped by the get_token method" if self.debug >= 1: print("shlex: pushing token " + repr(tok)) self.pushback.appendleft(tok) def push_source(self, newstream, newfile=None): "Push an input source onto the lexer's input source stack." # Modified by argcomplete: 2/3 compatibility if isinstance(newstream, basestring): newstream = StringIO(newstream) self.filestack.appendleft((self.infile, self.instream, self.lineno)) self.infile = newfile self.instream = newstream self.lineno = 1 if self.debug: if newfile is not None: print('shlex: pushing to file %s' % (self.infile,)) else: print('shlex: pushing to stream %s' % (self.instream,)) def pop_source(self): "Pop the input source stack." self.instream.close() (self.infile, self.instream, self.lineno) = self.filestack.popleft() if self.debug: print('shlex: popping to %s, line %d' \ % (self.instream, self.lineno)) self.state = ' ' def get_token(self): "Get a token from the input stream (or from stack if it's nonempty)" if self.pushback: tok = self.pushback.popleft() if self.debug >= 1: print("shlex: popping token " + repr(tok)) return tok # No pushback. Get a token. raw = self.read_token() # Handle inclusions if self.source is not None: while raw == self.source: spec = self.sourcehook(self.read_token()) if spec: (newfile, newstream) = spec self.push_source(newstream, newfile) raw = self.get_token() # Maybe we got EOF instead? while raw == self.eof: if not self.filestack: return self.eof else: self.pop_source() raw = self.get_token() # Neither inclusion nor EOF if self.debug >= 1: if raw != self.eof: print("shlex: token=" + repr(raw)) else: print("shlex: token=EOF") return raw def read_token(self): quoted = False escapedstate = ' ' while True: if self.punctuation_chars and self._pushback_chars: nextchar = self._pushback_chars.pop() else: nextchar = self.instream.read(1) if nextchar == '\n': self.lineno += 1 if self.debug >= 3: print("shlex: in state %r I see character: %r" % (self.state, nextchar)) if self.state is None: self.token = '' # past end of file break elif self.state == ' ': if not nextchar: self.state = None # end of file break elif nextchar in self.whitespace: if self.debug >= 2: print("shlex: I see whitespace in whitespace state") if self.token or (self.posix and quoted): break # emit current token else: continue elif nextchar in self.commenters: self.instream.readline() self.lineno += 1 elif self.posix and nextchar in self.escape: escapedstate = 'a' self.state = nextchar elif nextchar in self.wordchars: self.token = nextchar self.state = 'a' elif nextchar in self.punctuation_chars: self.token = nextchar self.state = 'c' elif nextchar in self.quotes: if not self.posix: self.token = nextchar self.state = nextchar elif self.whitespace_split: self.token = nextchar self.state = 'a' else: self.token = nextchar if self.token or (self.posix and quoted): break # emit current token else: continue elif self.state in self.quotes: quoted = True if not nextchar: # end of file if self.debug >= 2: print("shlex: I see EOF in quotes state") # XXX what error should be raised here? raise ValueError("No closing quotation") if nextchar == self.state: if not self.posix: self.token += nextchar self.state = ' ' break else: self.state = 'a' elif (self.posix and nextchar in self.escape and self.state in self.escapedquotes): escapedstate = self.state self.state = nextchar else: self.token += nextchar elif self.state in self.escape: if not nextchar: # end of file if self.debug >= 2: print("shlex: I see EOF in escape state") # XXX what error should be raised here? raise ValueError("No escaped character") # In posix shells, only the quote itself or the escape # character may be escaped within quotes. if (escapedstate in self.quotes and nextchar != self.state and nextchar != escapedstate): self.token += self.state self.token += nextchar self.state = escapedstate elif self.state in ('a', 'c'): if not nextchar: self.state = None # end of file break elif nextchar in self.whitespace: if self.debug >= 2: print("shlex: I see whitespace in word state") self.state = ' ' if self.token or (self.posix and quoted): break # emit current token else: continue elif nextchar in self.commenters: self.instream.readline() self.lineno += 1 if self.posix: self.state = ' ' if self.token or (self.posix and quoted): break # emit current token else: continue elif self.posix and nextchar in self.quotes: self.state = nextchar elif self.posix and nextchar in self.escape: escapedstate = 'a' self.state = nextchar elif self.state == 'c': if nextchar in self.punctuation_chars: self.token += nextchar else: if nextchar not in self.whitespace: self._pushback_chars.append(nextchar) self.state = ' ' break elif (nextchar in self.wordchars or nextchar in self.quotes or self.whitespace_split): self.token += nextchar # Modified by argcomplete: Record last wordbreak position if nextchar in self.wordbreaks: self.last_wordbreak_pos = len(self.token) - 1 else: if self.punctuation_chars: self._pushback_chars.append(nextchar) else: self.pushback.appendleft(nextchar) if self.debug >= 2: print("shlex: I see punctuation in word state") self.state = ' ' if self.token or (self.posix and quoted): break # emit current token else: continue result = self.token self.token = '' if self.posix and not quoted and result == '': result = None if self.debug > 1: if result: print("shlex: raw token=" + repr(result)) else: print("shlex: raw token=EOF") # Modified by argcomplete: Record last wordbreak position if self.state == ' ': self.last_wordbreak_pos = None return result def sourcehook(self, newfile): "Hook called on a filename to be sourced." if newfile[0] == '"': newfile = newfile[1:-1] # This implements cpp-like semantics for relative-path inclusion. # Modified by argcomplete: 2/3 compatibility if isinstance(self.infile, basestring) and not os.path.isabs(newfile): newfile = os.path.join(os.path.dirname(self.infile), newfile) return (newfile, open(newfile, "r")) def error_leader(self, infile=None, lineno=None): "Emit a C-compiler-like, Emacs-friendly error-message leader." if infile is None: infile = self.infile if lineno is None: lineno = self.lineno return "\"%s\", line %d: " % (infile, lineno) def __iter__(self): return self def __next__(self): token = self.get_token() if token == self.eof: raise StopIteration return token # Modified by argcomplete: 2/3 compatibility next = __next__ argcomplete-1.8.1/argcomplete.egg-info/0000755000076500000240000000000013040732051020630 5ustar kislyukstaff00000000000000argcomplete-1.8.1/argcomplete.egg-info/dependency_links.txt0000644000076500000240000000000113040732051024676 0ustar kislyukstaff00000000000000 argcomplete-1.8.1/argcomplete.egg-info/not-zip-safe0000644000076500000240000000000113040732043023057 0ustar kislyukstaff00000000000000 argcomplete-1.8.1/argcomplete.egg-info/PKG-INFO0000644000076500000240000004141013040732051021725 0ustar kislyukstaff00000000000000Metadata-Version: 1.1 Name: argcomplete Version: 1.8.1 Summary: Bash tab completion for argparse Home-page: https://github.com/kislyuk/argcomplete Author: Andrey Kislyuk Author-email: kislyuk@gmail.com License: Apache Software License Description: argcomplete - Bash tab completion for argparse ============================================== *Tab complete all the things!* Argcomplete provides easy, extensible command line tab completion of arguments for your Python script. It makes two assumptions: * You're using bash as your shell (limited support for zsh and tcsh is available) * You're using `argparse `_ to manage your command line arguments/options Argcomplete is particularly useful if your program has lots of options or subparsers, and if your program can dynamically suggest completions for your argument/option values (for example, if the user is browsing resources over the network). Installation ------------ :: pip install argcomplete activate-global-python-argcomplete See `Activating global completion`_ below for details about the second step (or if it reports an error). Refresh your bash environment (start a new shell or ``source /etc/profile``). Synopsis -------- Python code (e.g. ``my-awesome-script.py``): .. code-block:: python #!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK import argcomplete, argparse parser = argparse.ArgumentParser() ... argcomplete.autocomplete(parser) args = parser.parse_args() ... Shellcode (only necessary if global completion is not activated - see `Global completion`_ below), to be put in e.g. ``.bashrc``:: eval "$(register-python-argcomplete my-awesome-script.py)" Note that the script name is passed directly to ``complete``, meaning it is only tab completed when invoked exactly as it was registered. The above line will **not** allow you to complete ``./my-awesome-script.py``, or ``/path/to/my-awesome-script.py``. argcomplete.autocomplete(*parser*) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This method is the entry point to the module. It must be called **after** ArgumentParser construction is complete, but **before** the ``ArgumentParser.parse_args()`` method is called. The method looks for an environment variable that the completion hook shellcode sets, and if it's there, collects completions, prints them to the output stream (fd 8 by default), and exits. Otherwise, it returns to the caller immediately. .. admonition:: Side effects Argcomplete gets completions by running your program. It intercepts the execution flow at the moment ``argcomplete.autocomplete()`` is called. After sending completions, it exits using ``exit_method`` (``os._exit`` by default). This means if your program has any side effects that happen before ``argcomplete`` is called, those side effects will happen every time the user presses ```` (although anything your program prints to stdout or stderr will be suppressed). For this reason it's best to construct the argument parser and call ``argcomplete.autocomplete()`` as early as possible in your execution flow. .. admonition:: Performance If the program takes a long time to get to the point where ``argcomplete.autocomplete()`` is called, the tab completion process will feel sluggish, and the user may lose confidence in it. So it's also important to minimize the startup time of the program up to that point (for example, by deferring initialization or importing of large modules until after parsing options). Specifying completers --------------------- You can specify custom completion functions for your options and arguments. Two styles are supported: callable and readline-style. Callable completers are simpler. They are called with the following keyword arguments: * ``prefix``: The prefix text of the last word before the cursor on the command line. All returned completions should begin with this prefix. * ``action``: The ``argparse.Action`` instance that this completer was called for. * ``parser``: The ``argparse.ArgumentParser`` instance that the action was taken by. * ``parsed_args``: The result of argument parsing so far (the ``argparse.Namespace`` args object normally returned by ``ArgumentParser.parse_args()``). Completers should return their completions as a list of strings. An example completer for names of environment variables might look like this: .. code-block:: python def EnvironCompleter(prefix, **kwargs): return (v for v in os.environ if v.startswith(prefix)) To specify a completer for an argument or option, set the ``completer`` attribute of its associated action. An easy way to do this at definition time is: .. code-block:: python from argcomplete.completers import EnvironCompleter parser = argparse.ArgumentParser() parser.add_argument("--env-var1").completer = EnvironCompleter parser.add_argument("--env-var2").completer = EnvironCompleter argcomplete.autocomplete(parser) If you specify the ``choices`` keyword for an argparse option or argument (and don't specify a completer), it will be used for completions. A completer that is initialized with a set of all possible choices of values for its action might look like this: .. code-block:: python class ChoicesCompleter(object): def __init__(self, choices=[]): self.choices = [str(choice) for choice in choices] def __call__(self, prefix, **kwargs): return (c for c in self.choices if c.startswith(prefix)) The following two ways to specify a static set of choices are equivalent for completion purposes: .. code-block:: python from argcomplete.completers import ChoicesCompleter parser.add_argument("--protocol", choices=('http', 'https', 'ssh', 'rsync', 'wss')) parser.add_argument("--proto").completer=ChoicesCompleter(('http', 'https', 'ssh', 'rsync', 'wss')) Note that if you use the ``choices=`` option, argparse will show all these choices in the ``--help`` output by default. To prevent this, set ``metavar`` (like ``parser.add_argument("--protocol", metavar="PROTOCOL", choices=('http', 'https', 'ssh', 'rsync', 'wss'))``). The following `script `_ uses ``parsed_args`` and `Requests `_ to query GitHub for publicly known members of an organization and complete their names, then prints the member description: .. code-block:: python #!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK import argcomplete, argparse, requests, pprint def github_org_members(prefix, parsed_args, **kwargs): resource = "https://api.github.com/orgs/{org}/members".format(org=parsed_args.organization) return (member['login'] for member in requests.get(resource).json() if member['login'].startswith(prefix)) parser = argparse.ArgumentParser() parser.add_argument("--organization", help="GitHub organization") parser.add_argument("--member", help="GitHub member").completer = github_org_members argcomplete.autocomplete(parser) args = parser.parse_args() pprint.pprint(requests.get("https://api.github.com/users/{m}".format(m=args.member)).json()) `Try it `_ like this:: ./describe_github_user.py --organization heroku --member If you have a useful completer to add to the `completer library `_, send a pull request! Readline-style completers ~~~~~~~~~~~~~~~~~~~~~~~~~ The readline_ module defines a completer protocol in rlcompleter_. Readline-style completers are also supported by argcomplete, so you can use the same completer object both in an interactive readline-powered shell and on the bash command line. For example, you can use the readline-style completer provided by IPython_ to get introspective completions like you would get in the IPython shell: .. _readline: http://docs.python.org/2/library/readline.html .. _rlcompleter: http://docs.python.org/2/library/rlcompleter.html#completer-objects .. _IPython: http://ipython.org/ .. code-block:: python import IPython parser.add_argument("--python-name").completer = IPython.core.completer.Completer() You can also use `argcomplete.CompletionFinder.rl_complete `_ to plug your entire argparse parser as a readline completer. Printing warnings in completers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Normal stdout/stderr output is suspended when argcomplete runs. Sometimes, though, when the user presses ````, 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 Using a custom completion validator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, argcomplete validates your completions by checking if they start with the prefix given to the completer. You can override this validation check by supplying the ``validator`` keyword to ``argcomplete.autocomplete()``: .. code-block:: python def my_validator(current_input, keyword_to_check_against): # Pass through ALL options even if they don't all start with 'current_input' return True argcomplete.autocomplete(parser, validator=my_validator) Global completion ----------------- In global completion mode, you don't have to register each argcomplete-capable executable separately. Instead, bash will look for the string **PYTHON_ARGCOMPLETE_OK** in the first 1024 bytes of any executable that it's running completion for, and if it's found, follow the rest of the argcomplete protocol as described above. .. admonition:: Bash version compatibility Global completion requires bash support for ``complete -D``, which was introduced in bash 4.2. On OS X or older Linux systems, you will need to update bash to use this feature. Check the version of the running copy of bash with ``echo $BASH_VERSION``. On OS X, install bash via `Homebrew `_ (``brew install bash``), add ``/usr/local/bin/bash`` to ``/etc/shells``, and run ``chsh`` to change your shell. Global completion is not currently compatible with zsh. .. note:: If you use setuptools/distribute ``scripts`` or ``entry_points`` directives to package your module, argcomplete will follow the wrapper scripts to their destination and look for ``PYTHON_ARGCOMPLETE_OK`` in the destination code. Activating global completion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The script ``activate-global-python-argcomplete`` will try to install the file ``bash_completion.d/python-argcomplete.sh`` (`see on GitHub`_) into an appropriate location on your system (``/etc/bash_completion.d/`` or ``~/.bash_completion.d/``). If it fails, but you know the correct location of your bash completion scripts directory, you can specify it with ``--dest``:: activate-global-python-argcomplete --dest=/path/to/bash_completion.d Otherwise, you can redirect its shellcode output into a file:: activate-global-python-argcomplete --dest=- > file The file's contents should then be sourced in e.g. ``~/.bashrc``. .. _`see on GitHub`: https://github.com/kislyuk/argcomplete/blob/master/argcomplete/bash_completion.d/python-argcomplete.sh Tcsh Support ------------ To activate completions for tcsh use:: eval `register-python-argcomplete --shell tcsh my-awesome-script.py` The ``python-argcomplete-tcsh`` script provides completions for tcsh. The following is an example of the tcsh completion syntax for ``my-awesome-script.py`` emitted by ``register-python-argcomplete``:: complete my-awesome-script.py 'p@*@`python-argcomplete-tcsh my-awesome-script.py`@' Debugging --------- Set the ``_ARC_DEBUG`` variable in your shell to enable verbose debug output every time argcomplete runs. Alternatively, you can bypass the bash completion shellcode altogether, and interact with the Python code directly with something like this:: PROGNAME=./{YOUR_PY_SCRIPT} TEST_ARGS='some_arguments with autocompl' _ARC_DEBUG=1 COMP_LINE="$PROGNAME $TEST_ARGS" COMP_POINT=31 _ARGCOMPLETE=1 $PROGNAME 8>&1 9>>~/autocomplete_debug.log Then tail:: tail -f ~/autocomplete_debug.log Acknowledgments --------------- Inspired and informed by the optcomplete_ module by Martin Blais. .. _optcomplete: http://pypi.python.org/pypi/optcomplete Links ----- * `Project home page (GitHub) `_ * `Documentation (Read the Docs) `_ * `Package distribution (PyPI) `_ * `Change log `_ Bugs ~~~~ Please report bugs, issues, feature requests, etc. on `GitHub `_. License ------- Licensed under the terms of the `Apache License, Version 2.0 `_. .. image:: https://travis-ci.org/kislyuk/argcomplete.png :target: https://travis-ci.org/kislyuk/argcomplete .. image:: https://codecov.io/github/kislyuk/argcomplete/coverage.svg?branch=master :target: https://codecov.io/github/kislyuk/argcomplete?branch=master .. image:: https://img.shields.io/pypi/v/argcomplete.svg :target: https://pypi.python.org/pypi/argcomplete .. image:: https://img.shields.io/pypi/l/argcomplete.svg :target: https://pypi.python.org/pypi/argcomplete .. image:: https://readthedocs.org/projects/argcomplete/badge/?version=latest :target: https://argcomplete.readthedocs.org/ Platform: MacOS X Platform: Posix Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: POSIX Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Development Status :: 5 - Production/Stable Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Shells Classifier: Topic :: Terminals argcomplete-1.8.1/argcomplete.egg-info/requires.txt0000644000076500000240000000004613040732051023230 0ustar kislyukstaff00000000000000 [test] coverage flake8 pexpect wheel argcomplete-1.8.1/argcomplete.egg-info/SOURCES.txt0000644000076500000240000000127013040732051022514 0ustar kislyukstaff00000000000000Authors.rst Changes.rst LICENSE.rst MANIFEST.in README.rst setup.cfg setup.py argcomplete/__init__.py argcomplete/compat.py argcomplete/completers.py argcomplete/my_argparse.py argcomplete/my_shlex.py argcomplete.egg-info/PKG-INFO argcomplete.egg-info/SOURCES.txt argcomplete.egg-info/dependency_links.txt argcomplete.egg-info/not-zip-safe argcomplete.egg-info/requires.txt argcomplete.egg-info/top_level.txt argcomplete/bash_completion.d/python-argcomplete.sh scripts/activate-global-python-argcomplete scripts/python-argcomplete-check-easy-install-script scripts/python-argcomplete-tcsh scripts/register-python-argcomplete test/__init__.py test/__init__.pyc test/prog test/test.py test/test.pycargcomplete-1.8.1/argcomplete.egg-info/top_level.txt0000644000076500000240000000001413040732051023355 0ustar kislyukstaff00000000000000argcomplete argcomplete-1.8.1/Authors.rst0000644000076500000240000000004312730011252017006 0ustar kislyukstaff00000000000000Andrey Kislyuk argcomplete-1.8.1/Changes.rst0000644000076500000240000001502713040732027016746 0ustar kislyukstaff00000000000000Changes for v1.8.1 (2017-01-21) =============================== - Fix completion after tokens with wordbreak chars (#197) Changes for v1.8.0 (2017-01-19) =============================== This release contains work by @evanunderscore with numerous improvements to the handling of special characters in completions. - Simplify nospace handling in global completion (#195) - Specially handle all characters in COMP\_WORDBREAKS (#187) - Use setuptools tests-require directive, fixes #186 - Complete files using the specified interpreter (#192) - Fix completion for scripts run via python (#191) - Clarify argument to register-python-argcomplete (#190) - Fix handling of commas and other special chars (#172); handle more special characters (#189) - Fix handling of special characters in tcsh (#188) - Update my\_shlex to Python 3.6 version (#184) - Fix additional trailing space in exact matches (#183) - Adjust tests to handle development environments (#180) - Fix tcsh tests on OSX (#177); Update bash on OSX (#176); Check output of test setup command (#179) - Optionally disable duplicated flags (#143) - Add default\_completer option to CompletionFinder.\ **call** (#167) - Let bash add or suppress trailing space (#159) Changes for v1.7.0 (2016-11-30) =============================== - Restore parser to its original state to allow reuse after completion (#150). - Expose COMP\_TYPE environment variable (#157). Thanks to Matt Clay (@mattclay). - Test infrastructure and documentation improvements. Changes for v1.6.0 (2016-10-20) =============================== - Add support for tcsh (#155) - Fix handling of unquoted completions containing $ (#154) - Don't insert unnecessary leading quote char in completions (#152) - Fix parser reuse with positional arguments (#149) - Tests: Add simple pexpect tests for bash (#153); Add test case to verify #20 is fixed (#148) - Thanks to @davvid and @evanunderscore for their work on this release. Changes for v1.5.1 (2016-10-11) =============================== - Packaging fix Changes for v1.5.0 (2016-10-11) =============================== - Do not suggest options from mutually exclusive groups (#145). Version 1.4.1 (2016-06-14) ========================== - activate-global-python-argcomplete runs on Homebrew out of the box Version 1.4.0 (2016-06-10) ========================== - Correctly handle suggestions for positionals with variable-length nargs. Thanks to @evanunderscore (#132, #133). Version 1.3.0 (2016-06-01) ========================== - Correctly handle suggestions with custom nargs for optionals. Thanks to @evanunderscore (#131). Version 1.2.0 (2016-05-25) ========================== - Fix propagation of partially parsed subparser namespace into parent parser namespace upon subparser failure due to partial args. This allows completers to access partial parse results for subparser optionals in parsed_args (#114). - The default completer can now be specified when manually instantiating CompletionFinder. Thanks to @avylove (#130). Version 1.1.1 (2016-03-22) ========================== - Use FilesCompleter as default completer fallback (#120). Version 1.1.0 (2016-02-21) ========================== - Recognize subclasses of argparse._SubParsersAction. Thanks to Stephen Koo (#118). - Support parsed_args in custom completers with missing args. Thanks to Dan Kilman (#124). - Non-ASCII support in FilesCompleter. - Automatically enable FilesCompleter for argparse.FileType arguments. Version 1.0.0 (2015-08-22) ========================== - Don't print args with suppressed help by default; add ``argcomplete.autocomplete(print_suppressed=True)`` to control this behavior (#113). Version 0.9.0 (2015-07-03) ========================== - Fix always_complete_options=False support (#115). Version 0.8.9 (2015-06-01) ========================== - Correct doc filename in setup.cfg (fixes bdist_rpm failure, Issue 111). - Make context managers exception-safe. Thanks to Mikołaj Siedlarek (pull request #110). Version 0.8.8 (2015-05-01) ========================== - Build and upload universal wheel packages in release. - Fix issue with non-string choices for arguments. Thanks to @neizod (pull request #107). - Improve non-ascii argparse argument support on Python 2.7. Version 0.8.7 (2015-04-11) ========================== - register-python-argcomplete: add option to avoid default readline completion. Thanks to @drmalex07 (pull request #99). Version 0.8.6 (2015-04-11) ========================== - Expand tilde in script name, allowing argcomplete to work when invoking scripts from one's home directory. Thanks to @VorpalBlade (Issue 104). Version 0.8.5 (2015-04-07) ========================== - Fix issues related to using argcomplete in a REPL environement. - New helper method for custom completion display. - Expand test suite; formatting cleanup. Version 0.8.4 (2014-12-11) ========================== - Fix issue related to using argcomplete in a REPL environement. Thanks to @wapiflapi (pull request #91). Version 0.8.3 (2014-11-09) ========================== - Fix multiple issues related to using argcomplete in a REPL environement. Thanks to @wapiflapi (pull request #90). Version 0.8.2 (2014-11-03) ========================== - Don't strip colon prefix in completion results if COMP_WORDBREAKS does not contain a colon. Thanks to @berezv (pull request #88). Version 0.8.1 (2014-07-02) ========================== - Use complete --nospace to avoid issues with directory completion. Version 0.8.0 (2014-04-07) ========================== - Refactor main body of code into a class to enable subclassing and overriding of functionality (Issue #78). Version 0.7.1 (2014-03-29) ========================== - New keyword option "argcomplete.autocomplete(validator=...)" to supply a custom validator or bypass default validation. Thanks to @thijsdezoete (Issue #77). - Document debug options. Version 0.7.0 (2014-01-19) ========================== - New keyword option "argcomplete.autocomplete(exclude=[...])" to suppress options (Issue #74). - More speedups to code path for global completion hook negative result. Version 0.6.9 (2014-01-19) ========================== - Fix handling of development mode script wrappers. Thanks to @jmlopez-rod and @dcosson (Issue #69). - Speed up code path for global completion hook negative result by loading pkg_resources on demand. Version 0.6.8 (2014-01-18) ========================== - Begin tracking changes in changelog. - Add completion support for PBR installed scripts (PR #71). - Detect easy-install shims with shebang lines that contain Py instead of py (Issue #69). argcomplete-1.8.1/LICENSE.rst0000644000076500000240000002367612730011252016464 0ustar kislyukstaff00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS argcomplete-1.8.1/MANIFEST.in0000644000076500000240000000010513040207436016372 0ustar kislyukstaff00000000000000include argcomplete/bash_completion.d/* include *.rst include test/* argcomplete-1.8.1/PKG-INFO0000644000076500000240000004141013040732051015731 0ustar kislyukstaff00000000000000Metadata-Version: 1.1 Name: argcomplete Version: 1.8.1 Summary: Bash tab completion for argparse Home-page: https://github.com/kislyuk/argcomplete Author: Andrey Kislyuk Author-email: kislyuk@gmail.com License: Apache Software License Description: argcomplete - Bash tab completion for argparse ============================================== *Tab complete all the things!* Argcomplete provides easy, extensible command line tab completion of arguments for your Python script. It makes two assumptions: * You're using bash as your shell (limited support for zsh and tcsh is available) * You're using `argparse `_ to manage your command line arguments/options Argcomplete is particularly useful if your program has lots of options or subparsers, and if your program can dynamically suggest completions for your argument/option values (for example, if the user is browsing resources over the network). Installation ------------ :: pip install argcomplete activate-global-python-argcomplete See `Activating global completion`_ below for details about the second step (or if it reports an error). Refresh your bash environment (start a new shell or ``source /etc/profile``). Synopsis -------- Python code (e.g. ``my-awesome-script.py``): .. code-block:: python #!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK import argcomplete, argparse parser = argparse.ArgumentParser() ... argcomplete.autocomplete(parser) args = parser.parse_args() ... Shellcode (only necessary if global completion is not activated - see `Global completion`_ below), to be put in e.g. ``.bashrc``:: eval "$(register-python-argcomplete my-awesome-script.py)" Note that the script name is passed directly to ``complete``, meaning it is only tab completed when invoked exactly as it was registered. The above line will **not** allow you to complete ``./my-awesome-script.py``, or ``/path/to/my-awesome-script.py``. argcomplete.autocomplete(*parser*) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This method is the entry point to the module. It must be called **after** ArgumentParser construction is complete, but **before** the ``ArgumentParser.parse_args()`` method is called. The method looks for an environment variable that the completion hook shellcode sets, and if it's there, collects completions, prints them to the output stream (fd 8 by default), and exits. Otherwise, it returns to the caller immediately. .. admonition:: Side effects Argcomplete gets completions by running your program. It intercepts the execution flow at the moment ``argcomplete.autocomplete()`` is called. After sending completions, it exits using ``exit_method`` (``os._exit`` by default). This means if your program has any side effects that happen before ``argcomplete`` is called, those side effects will happen every time the user presses ```` (although anything your program prints to stdout or stderr will be suppressed). For this reason it's best to construct the argument parser and call ``argcomplete.autocomplete()`` as early as possible in your execution flow. .. admonition:: Performance If the program takes a long time to get to the point where ``argcomplete.autocomplete()`` is called, the tab completion process will feel sluggish, and the user may lose confidence in it. So it's also important to minimize the startup time of the program up to that point (for example, by deferring initialization or importing of large modules until after parsing options). Specifying completers --------------------- You can specify custom completion functions for your options and arguments. Two styles are supported: callable and readline-style. Callable completers are simpler. They are called with the following keyword arguments: * ``prefix``: The prefix text of the last word before the cursor on the command line. All returned completions should begin with this prefix. * ``action``: The ``argparse.Action`` instance that this completer was called for. * ``parser``: The ``argparse.ArgumentParser`` instance that the action was taken by. * ``parsed_args``: The result of argument parsing so far (the ``argparse.Namespace`` args object normally returned by ``ArgumentParser.parse_args()``). Completers should return their completions as a list of strings. An example completer for names of environment variables might look like this: .. code-block:: python def EnvironCompleter(prefix, **kwargs): return (v for v in os.environ if v.startswith(prefix)) To specify a completer for an argument or option, set the ``completer`` attribute of its associated action. An easy way to do this at definition time is: .. code-block:: python from argcomplete.completers import EnvironCompleter parser = argparse.ArgumentParser() parser.add_argument("--env-var1").completer = EnvironCompleter parser.add_argument("--env-var2").completer = EnvironCompleter argcomplete.autocomplete(parser) If you specify the ``choices`` keyword for an argparse option or argument (and don't specify a completer), it will be used for completions. A completer that is initialized with a set of all possible choices of values for its action might look like this: .. code-block:: python class ChoicesCompleter(object): def __init__(self, choices=[]): self.choices = [str(choice) for choice in choices] def __call__(self, prefix, **kwargs): return (c for c in self.choices if c.startswith(prefix)) The following two ways to specify a static set of choices are equivalent for completion purposes: .. code-block:: python from argcomplete.completers import ChoicesCompleter parser.add_argument("--protocol", choices=('http', 'https', 'ssh', 'rsync', 'wss')) parser.add_argument("--proto").completer=ChoicesCompleter(('http', 'https', 'ssh', 'rsync', 'wss')) Note that if you use the ``choices=`` option, argparse will show all these choices in the ``--help`` output by default. To prevent this, set ``metavar`` (like ``parser.add_argument("--protocol", metavar="PROTOCOL", choices=('http', 'https', 'ssh', 'rsync', 'wss'))``). The following `script `_ uses ``parsed_args`` and `Requests `_ to query GitHub for publicly known members of an organization and complete their names, then prints the member description: .. code-block:: python #!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK import argcomplete, argparse, requests, pprint def github_org_members(prefix, parsed_args, **kwargs): resource = "https://api.github.com/orgs/{org}/members".format(org=parsed_args.organization) return (member['login'] for member in requests.get(resource).json() if member['login'].startswith(prefix)) parser = argparse.ArgumentParser() parser.add_argument("--organization", help="GitHub organization") parser.add_argument("--member", help="GitHub member").completer = github_org_members argcomplete.autocomplete(parser) args = parser.parse_args() pprint.pprint(requests.get("https://api.github.com/users/{m}".format(m=args.member)).json()) `Try it `_ like this:: ./describe_github_user.py --organization heroku --member If you have a useful completer to add to the `completer library `_, send a pull request! Readline-style completers ~~~~~~~~~~~~~~~~~~~~~~~~~ The readline_ module defines a completer protocol in rlcompleter_. Readline-style completers are also supported by argcomplete, so you can use the same completer object both in an interactive readline-powered shell and on the bash command line. For example, you can use the readline-style completer provided by IPython_ to get introspective completions like you would get in the IPython shell: .. _readline: http://docs.python.org/2/library/readline.html .. _rlcompleter: http://docs.python.org/2/library/rlcompleter.html#completer-objects .. _IPython: http://ipython.org/ .. code-block:: python import IPython parser.add_argument("--python-name").completer = IPython.core.completer.Completer() You can also use `argcomplete.CompletionFinder.rl_complete `_ to plug your entire argparse parser as a readline completer. Printing warnings in completers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Normal stdout/stderr output is suspended when argcomplete runs. Sometimes, though, when the user presses ````, 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 Using a custom completion validator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, argcomplete validates your completions by checking if they start with the prefix given to the completer. You can override this validation check by supplying the ``validator`` keyword to ``argcomplete.autocomplete()``: .. code-block:: python def my_validator(current_input, keyword_to_check_against): # Pass through ALL options even if they don't all start with 'current_input' return True argcomplete.autocomplete(parser, validator=my_validator) Global completion ----------------- In global completion mode, you don't have to register each argcomplete-capable executable separately. Instead, bash will look for the string **PYTHON_ARGCOMPLETE_OK** in the first 1024 bytes of any executable that it's running completion for, and if it's found, follow the rest of the argcomplete protocol as described above. .. admonition:: Bash version compatibility Global completion requires bash support for ``complete -D``, which was introduced in bash 4.2. On OS X or older Linux systems, you will need to update bash to use this feature. Check the version of the running copy of bash with ``echo $BASH_VERSION``. On OS X, install bash via `Homebrew `_ (``brew install bash``), add ``/usr/local/bin/bash`` to ``/etc/shells``, and run ``chsh`` to change your shell. Global completion is not currently compatible with zsh. .. note:: If you use setuptools/distribute ``scripts`` or ``entry_points`` directives to package your module, argcomplete will follow the wrapper scripts to their destination and look for ``PYTHON_ARGCOMPLETE_OK`` in the destination code. Activating global completion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The script ``activate-global-python-argcomplete`` will try to install the file ``bash_completion.d/python-argcomplete.sh`` (`see on GitHub`_) into an appropriate location on your system (``/etc/bash_completion.d/`` or ``~/.bash_completion.d/``). If it fails, but you know the correct location of your bash completion scripts directory, you can specify it with ``--dest``:: activate-global-python-argcomplete --dest=/path/to/bash_completion.d Otherwise, you can redirect its shellcode output into a file:: activate-global-python-argcomplete --dest=- > file The file's contents should then be sourced in e.g. ``~/.bashrc``. .. _`see on GitHub`: https://github.com/kislyuk/argcomplete/blob/master/argcomplete/bash_completion.d/python-argcomplete.sh Tcsh Support ------------ To activate completions for tcsh use:: eval `register-python-argcomplete --shell tcsh my-awesome-script.py` The ``python-argcomplete-tcsh`` script provides completions for tcsh. The following is an example of the tcsh completion syntax for ``my-awesome-script.py`` emitted by ``register-python-argcomplete``:: complete my-awesome-script.py 'p@*@`python-argcomplete-tcsh my-awesome-script.py`@' Debugging --------- Set the ``_ARC_DEBUG`` variable in your shell to enable verbose debug output every time argcomplete runs. Alternatively, you can bypass the bash completion shellcode altogether, and interact with the Python code directly with something like this:: PROGNAME=./{YOUR_PY_SCRIPT} TEST_ARGS='some_arguments with autocompl' _ARC_DEBUG=1 COMP_LINE="$PROGNAME $TEST_ARGS" COMP_POINT=31 _ARGCOMPLETE=1 $PROGNAME 8>&1 9>>~/autocomplete_debug.log Then tail:: tail -f ~/autocomplete_debug.log Acknowledgments --------------- Inspired and informed by the optcomplete_ module by Martin Blais. .. _optcomplete: http://pypi.python.org/pypi/optcomplete Links ----- * `Project home page (GitHub) `_ * `Documentation (Read the Docs) `_ * `Package distribution (PyPI) `_ * `Change log `_ Bugs ~~~~ Please report bugs, issues, feature requests, etc. on `GitHub `_. License ------- Licensed under the terms of the `Apache License, Version 2.0 `_. .. image:: https://travis-ci.org/kislyuk/argcomplete.png :target: https://travis-ci.org/kislyuk/argcomplete .. image:: https://codecov.io/github/kislyuk/argcomplete/coverage.svg?branch=master :target: https://codecov.io/github/kislyuk/argcomplete?branch=master .. image:: https://img.shields.io/pypi/v/argcomplete.svg :target: https://pypi.python.org/pypi/argcomplete .. image:: https://img.shields.io/pypi/l/argcomplete.svg :target: https://pypi.python.org/pypi/argcomplete .. image:: https://readthedocs.org/projects/argcomplete/badge/?version=latest :target: https://argcomplete.readthedocs.org/ Platform: MacOS X Platform: Posix Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: POSIX Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Development Status :: 5 - Production/Stable Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Shells Classifier: Topic :: Terminals argcomplete-1.8.1/README.rst0000644000076500000240000003257213040207436016340 0ustar kislyukstaff00000000000000argcomplete - Bash tab completion for argparse ============================================== *Tab complete all the things!* Argcomplete provides easy, extensible command line tab completion of arguments for your Python script. It makes two assumptions: * You're using bash as your shell (limited support for zsh and tcsh is available) * You're using `argparse `_ to manage your command line arguments/options Argcomplete is particularly useful if your program has lots of options or subparsers, and if your program can dynamically suggest completions for your argument/option values (for example, if the user is browsing resources over the network). Installation ------------ :: pip install argcomplete activate-global-python-argcomplete See `Activating global completion`_ below for details about the second step (or if it reports an error). Refresh your bash environment (start a new shell or ``source /etc/profile``). Synopsis -------- Python code (e.g. ``my-awesome-script.py``): .. code-block:: python #!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK import argcomplete, argparse parser = argparse.ArgumentParser() ... argcomplete.autocomplete(parser) args = parser.parse_args() ... Shellcode (only necessary if global completion is not activated - see `Global completion`_ below), to be put in e.g. ``.bashrc``:: eval "$(register-python-argcomplete my-awesome-script.py)" Note that the script name is passed directly to ``complete``, meaning it is only tab completed when invoked exactly as it was registered. The above line will **not** allow you to complete ``./my-awesome-script.py``, or ``/path/to/my-awesome-script.py``. argcomplete.autocomplete(*parser*) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This method is the entry point to the module. It must be called **after** ArgumentParser construction is complete, but **before** the ``ArgumentParser.parse_args()`` method is called. The method looks for an environment variable that the completion hook shellcode sets, and if it's there, collects completions, prints them to the output stream (fd 8 by default), and exits. Otherwise, it returns to the caller immediately. .. admonition:: Side effects Argcomplete gets completions by running your program. It intercepts the execution flow at the moment ``argcomplete.autocomplete()`` is called. After sending completions, it exits using ``exit_method`` (``os._exit`` by default). This means if your program has any side effects that happen before ``argcomplete`` is called, those side effects will happen every time the user presses ```` (although anything your program prints to stdout or stderr will be suppressed). For this reason it's best to construct the argument parser and call ``argcomplete.autocomplete()`` as early as possible in your execution flow. .. admonition:: Performance If the program takes a long time to get to the point where ``argcomplete.autocomplete()`` is called, the tab completion process will feel sluggish, and the user may lose confidence in it. So it's also important to minimize the startup time of the program up to that point (for example, by deferring initialization or importing of large modules until after parsing options). Specifying completers --------------------- You can specify custom completion functions for your options and arguments. Two styles are supported: callable and readline-style. Callable completers are simpler. They are called with the following keyword arguments: * ``prefix``: The prefix text of the last word before the cursor on the command line. All returned completions should begin with this prefix. * ``action``: The ``argparse.Action`` instance that this completer was called for. * ``parser``: The ``argparse.ArgumentParser`` instance that the action was taken by. * ``parsed_args``: The result of argument parsing so far (the ``argparse.Namespace`` args object normally returned by ``ArgumentParser.parse_args()``). Completers should return their completions as a list of strings. An example completer for names of environment variables might look like this: .. code-block:: python def EnvironCompleter(prefix, **kwargs): return (v for v in os.environ if v.startswith(prefix)) To specify a completer for an argument or option, set the ``completer`` attribute of its associated action. An easy way to do this at definition time is: .. code-block:: python from argcomplete.completers import EnvironCompleter parser = argparse.ArgumentParser() parser.add_argument("--env-var1").completer = EnvironCompleter parser.add_argument("--env-var2").completer = EnvironCompleter argcomplete.autocomplete(parser) If you specify the ``choices`` keyword for an argparse option or argument (and don't specify a completer), it will be used for completions. A completer that is initialized with a set of all possible choices of values for its action might look like this: .. code-block:: python class ChoicesCompleter(object): def __init__(self, choices=[]): self.choices = [str(choice) for choice in choices] def __call__(self, prefix, **kwargs): return (c for c in self.choices if c.startswith(prefix)) The following two ways to specify a static set of choices are equivalent for completion purposes: .. code-block:: python from argcomplete.completers import ChoicesCompleter parser.add_argument("--protocol", choices=('http', 'https', 'ssh', 'rsync', 'wss')) parser.add_argument("--proto").completer=ChoicesCompleter(('http', 'https', 'ssh', 'rsync', 'wss')) Note that if you use the ``choices=`` option, argparse will show all these choices in the ``--help`` output by default. To prevent this, set ``metavar`` (like ``parser.add_argument("--protocol", metavar="PROTOCOL", choices=('http', 'https', 'ssh', 'rsync', 'wss'))``). The following `script `_ uses ``parsed_args`` and `Requests `_ to query GitHub for publicly known members of an organization and complete their names, then prints the member description: .. code-block:: python #!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK import argcomplete, argparse, requests, pprint def github_org_members(prefix, parsed_args, **kwargs): resource = "https://api.github.com/orgs/{org}/members".format(org=parsed_args.organization) return (member['login'] for member in requests.get(resource).json() if member['login'].startswith(prefix)) parser = argparse.ArgumentParser() parser.add_argument("--organization", help="GitHub organization") parser.add_argument("--member", help="GitHub member").completer = github_org_members argcomplete.autocomplete(parser) args = parser.parse_args() pprint.pprint(requests.get("https://api.github.com/users/{m}".format(m=args.member)).json()) `Try it `_ like this:: ./describe_github_user.py --organization heroku --member If you have a useful completer to add to the `completer library `_, send a pull request! Readline-style completers ~~~~~~~~~~~~~~~~~~~~~~~~~ The readline_ module defines a completer protocol in rlcompleter_. Readline-style completers are also supported by argcomplete, so you can use the same completer object both in an interactive readline-powered shell and on the bash command line. For example, you can use the readline-style completer provided by IPython_ to get introspective completions like you would get in the IPython shell: .. _readline: http://docs.python.org/2/library/readline.html .. _rlcompleter: http://docs.python.org/2/library/rlcompleter.html#completer-objects .. _IPython: http://ipython.org/ .. code-block:: python import IPython parser.add_argument("--python-name").completer = IPython.core.completer.Completer() You can also use `argcomplete.CompletionFinder.rl_complete `_ to plug your entire argparse parser as a readline completer. Printing warnings in completers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Normal stdout/stderr output is suspended when argcomplete runs. Sometimes, though, when the user presses ````, 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 Using a custom completion validator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, argcomplete validates your completions by checking if they start with the prefix given to the completer. You can override this validation check by supplying the ``validator`` keyword to ``argcomplete.autocomplete()``: .. code-block:: python def my_validator(current_input, keyword_to_check_against): # Pass through ALL options even if they don't all start with 'current_input' return True argcomplete.autocomplete(parser, validator=my_validator) Global completion ----------------- In global completion mode, you don't have to register each argcomplete-capable executable separately. Instead, bash will look for the string **PYTHON_ARGCOMPLETE_OK** in the first 1024 bytes of any executable that it's running completion for, and if it's found, follow the rest of the argcomplete protocol as described above. .. admonition:: Bash version compatibility Global completion requires bash support for ``complete -D``, which was introduced in bash 4.2. On OS X or older Linux systems, you will need to update bash to use this feature. Check the version of the running copy of bash with ``echo $BASH_VERSION``. On OS X, install bash via `Homebrew `_ (``brew install bash``), add ``/usr/local/bin/bash`` to ``/etc/shells``, and run ``chsh`` to change your shell. Global completion is not currently compatible with zsh. .. note:: If you use setuptools/distribute ``scripts`` or ``entry_points`` directives to package your module, argcomplete will follow the wrapper scripts to their destination and look for ``PYTHON_ARGCOMPLETE_OK`` in the destination code. Activating global completion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The script ``activate-global-python-argcomplete`` will try to install the file ``bash_completion.d/python-argcomplete.sh`` (`see on GitHub`_) into an appropriate location on your system (``/etc/bash_completion.d/`` or ``~/.bash_completion.d/``). If it fails, but you know the correct location of your bash completion scripts directory, you can specify it with ``--dest``:: activate-global-python-argcomplete --dest=/path/to/bash_completion.d Otherwise, you can redirect its shellcode output into a file:: activate-global-python-argcomplete --dest=- > file The file's contents should then be sourced in e.g. ``~/.bashrc``. .. _`see on GitHub`: https://github.com/kislyuk/argcomplete/blob/master/argcomplete/bash_completion.d/python-argcomplete.sh Tcsh Support ------------ To activate completions for tcsh use:: eval `register-python-argcomplete --shell tcsh my-awesome-script.py` The ``python-argcomplete-tcsh`` script provides completions for tcsh. The following is an example of the tcsh completion syntax for ``my-awesome-script.py`` emitted by ``register-python-argcomplete``:: complete my-awesome-script.py 'p@*@`python-argcomplete-tcsh my-awesome-script.py`@' Debugging --------- Set the ``_ARC_DEBUG`` variable in your shell to enable verbose debug output every time argcomplete runs. Alternatively, you can bypass the bash completion shellcode altogether, and interact with the Python code directly with something like this:: PROGNAME=./{YOUR_PY_SCRIPT} TEST_ARGS='some_arguments with autocompl' _ARC_DEBUG=1 COMP_LINE="$PROGNAME $TEST_ARGS" COMP_POINT=31 _ARGCOMPLETE=1 $PROGNAME 8>&1 9>>~/autocomplete_debug.log Then tail:: tail -f ~/autocomplete_debug.log Acknowledgments --------------- Inspired and informed by the optcomplete_ module by Martin Blais. .. _optcomplete: http://pypi.python.org/pypi/optcomplete Links ----- * `Project home page (GitHub) `_ * `Documentation (Read the Docs) `_ * `Package distribution (PyPI) `_ * `Change log `_ Bugs ~~~~ Please report bugs, issues, feature requests, etc. on `GitHub `_. License ------- Licensed under the terms of the `Apache License, Version 2.0 `_. .. image:: https://travis-ci.org/kislyuk/argcomplete.png :target: https://travis-ci.org/kislyuk/argcomplete .. image:: https://codecov.io/github/kislyuk/argcomplete/coverage.svg?branch=master :target: https://codecov.io/github/kislyuk/argcomplete?branch=master .. image:: https://img.shields.io/pypi/v/argcomplete.svg :target: https://pypi.python.org/pypi/argcomplete .. image:: https://img.shields.io/pypi/l/argcomplete.svg :target: https://pypi.python.org/pypi/argcomplete .. image:: https://readthedocs.org/projects/argcomplete/badge/?version=latest :target: https://argcomplete.readthedocs.org/ argcomplete-1.8.1/scripts/0000755000076500000240000000000013040732051016323 5ustar kislyukstaff00000000000000argcomplete-1.8.1/scripts/activate-global-python-argcomplete0000755000076500000240000000657713040207436025151 0ustar kislyukstaff00000000000000#!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK # Copyright 2012-2013, Andrey Kislyuk and argcomplete contributors. # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. ''' Activate the generic bash-completion script for the argcomplete module. ''' import os, sys, argparse, argcomplete, shutil, fileinput parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) dest_opt = parser.add_argument("--dest", default="/etc/bash_completion.d", help="Specify the bash completion modules directory to install into") parser.add_argument("--user", help="Install into user directory (~/.bash_completion.d/)", action='store_true') parser.add_argument("--no-defaults", dest="use_defaults", action="store_false", default=True, help="When no matches are generated, do not fallback to readline\'s default completion") parser.add_argument("--complete-arguments", nargs=argparse.REMAINDER, help="arguments to call complete with; use of this option discards default options") argcomplete.autocomplete(parser) args = parser.parse_args() if args.user: args.dest = os.path.expanduser("~/.bash_completion.d/") if not os.path.exists(args.dest): try: os.mkdir(args.dest) except Exception as e: parser.error("Path {d} does not exist and could not be created: {e}".format(d=args.dest, e=e)) elif not os.path.exists(args.dest) and args.dest != '-': if sys.platform == 'darwin' and args.dest == dest_opt.default and os.path.exists("/usr/local" + dest_opt.default): args.dest = "/usr/local" + dest_opt.default else: parser.error("Path {d} does not exist".format(d=args.dest)) activator = os.path.join(os.path.dirname(argcomplete.__file__), 'bash_completion.d', 'python-argcomplete.sh') if args.complete_arguments is None: complete_options = '-o default -o bashdefault' if args.use_defaults else '-o bashdefault' else: complete_options = " ".join(args.complete_arguments) complete_call = "complete{} -D -F _python_argcomplete_global".format(" " + complete_options if complete_options else "") def replaceCompleteCall(line): if line.startswith("complete") and "_python_argcomplete_global" in line: return complete_call + ('\n' if line.endswith('\n') else '') else: return line if args.dest == '-': for l in open(activator): sys.stdout.write(replaceCompleteCall(l)) else: dest = os.path.join(args.dest, "python-argcomplete.sh") sys.stdout.write("Installing bash completion script " + dest) if not args.use_defaults: sys.stdout.write(" without -o default") elif args.complete_arguments: sys.stdout.write(" with options: " + complete_options) sys.stdout.write("\n") try: shutil.copy(activator, dest) if not args.complete_arguments is None or not args.use_defaults: for l in fileinput.input(dest, inplace=True): # fileinput with inplace=True redirects stdout to the edited file sys.stdout.write(replaceCompleteCall(l)) except Exception as e: err = str(e) if args.dest == dest_opt.default: err += "\nPlease try --user to install into a user directory, or --dest to specify the bash completion modules directory" parser.error(err) argcomplete-1.8.1/scripts/python-argcomplete-check-easy-install-script0000755000076500000240000000477612730026236027076 0ustar kislyukstaff00000000000000#!/usr/bin/env python # Copyright 2012-2013, Andrey Kislyuk and argcomplete contributors. # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. ''' This script is part of the Python argcomplete package (https://github.com/kislyuk/argcomplete). It is used to check if an EASY-INSTALL-SCRIPT wrapper redirects to a script that contains the string "PYTHON_ARGCOMPLETE_OK". If you have enabled global completion in argcomplete, the completion hook will run it every time you press in your shell. Usage: python-argcomplete-check-easy-install-script ''' import sys if len(sys.argv) != 2: sys.exit(__doc__) sys.tracebacklimit = 0 with open(sys.argv[1]) as fh: line1, head = fh.read(1024).split("\n", 1)[:2] if line1.startswith('#') and ('py' in line1 or 'Py' in line1): import re lines = head.split("\n", 12) for line in lines: if line.startswith("# EASY-INSTALL-SCRIPT"): import pkg_resources dist, script = re.match("# EASY-INSTALL-SCRIPT: '(.+)','(.+)'", line).groups() if "PYTHON_ARGCOMPLETE_OK" in pkg_resources.get_distribution(dist).get_metadata('scripts/' + script): exit(0) elif line.startswith("# EASY-INSTALL-ENTRY-SCRIPT"): dist, group, name = re.match("# EASY-INSTALL-ENTRY-SCRIPT: '(.+)','(.+)','(.+)'", line).groups() import pkg_resources, pkgutil module_name = pkg_resources.get_distribution(dist).get_entry_info(group, name).module_name with open(pkgutil.get_loader(module_name).get_filename()) as mod_fh: if "PYTHON_ARGCOMPLETE_OK" in mod_fh.read(1024): exit(0) elif line.startswith("# EASY-INSTALL-DEV-SCRIPT"): for line2 in lines: if line2.startswith('__file__'): filename = re.match("__file__ = '(.+)'", line2).group(1) with open(filename) as mod_fh: if "PYTHON_ARGCOMPLETE_OK" in mod_fh.read(1024): exit(0) elif line.startswith("# PBR Generated"): module = re.search("from (.*) import", head).groups()[0] import pkg_resources, pkgutil with open(pkgutil.get_loader(module).get_filename()) as mod_fh: if "PYTHON_ARGCOMPLETE_OK" in mod_fh.read(1024): exit(0) exit(1) argcomplete-1.8.1/scripts/python-argcomplete-tcsh0000755000076500000240000000047213040207436023040 0ustar kislyukstaff00000000000000#!/bin/sh IFS= export IFS COMP_WORDBREAKS= export COMP_WORDBREAKS COMP_TYPE= export COMP_TYPE COMP_LINE=${COMMAND_LINE} export COMP_LINE COMP_POINT=${#COMMAND_LINE} export COMP_POINT _ARGCOMPLETE=1 export _ARGCOMPLETE _ARGCOMPLETE_SHELL=tcsh export _ARGCOMPLETE_SHELL "$1" 8>&1 9>&2 1>/dev/null 2>/dev/null argcomplete-1.8.1/scripts/register-python-argcomplete0000755000076500000240000000515313040207436023724 0ustar kislyukstaff00000000000000#!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK # Copyright 2012-2013, Andrey Kislyuk and argcomplete contributors. # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. ''' Register a Python executable for use with the argcomplete module. To perform the registration, source the output of this script in your bash shell (quote the output to avoid interpolation). Example: $ eval "$(register-python-argcomplete my-favorite-script.py)" For Tcsh $ eval `register-python-argcomplete --shell tcsh my-favorite-script.py` ''' import sys import argparse shellcode = r''' _python_argcomplete() { local IFS=$'\013' local SUPPRESS_SPACE=0 if compopt +o nospace 2> /dev/null; then SUPPRESS_SPACE=1 fi COMPREPLY=( $(IFS="$IFS" \ COMP_LINE="$COMP_LINE" \ COMP_POINT="$COMP_POINT" \ COMP_TYPE="$COMP_TYPE" \ _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \ _ARGCOMPLETE=1 \ _ARGCOMPLETE_SUPPRESS_SPACE=$SUPPRESS_SPACE \ "$1" 8>&1 9>&2 1>/dev/null 2>/dev/null) ) if [[ $? != 0 ]]; then unset COMPREPLY elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "$COMPREPLY" =~ [=/:]$ ]]; then compopt -o nospace fi } complete %(complete_opts)s -F _python_argcomplete "%(executable)s" ''' tcshcode = '''\ complete "%(executable)s" 'p@*@`python-argcomplete-tcsh "%(executable)s"`@' ''' parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument( '--no-defaults', dest='use_defaults', action='store_false', default=True, help='When no matches are generated, do not fallback to readline\'s default completion') parser.add_argument( '--complete-arguments', nargs=argparse.REMAINDER, help='arguments to call complete with; use of this option discards default options') parser.add_argument( '-s', '--shell', choices=('bash', 'tcsh'), default='bash', help='output code for the specified shell') parser.add_argument( 'executable', help='executable to completed (when invoked by exactly this name)') if len(sys.argv) == 1: parser.print_help() sys.exit(1) args = parser.parse_args() if args.complete_arguments is None: complete_options = '-o nospace -o default' if args.use_defaults else '-o nospace' else: complete_options = " ".join(args.complete_arguments) if args.shell == 'bash': code = shellcode else: code = tcshcode sys.stdout.write(code % dict( complete_opts=complete_options, executable=args.executable )) argcomplete-1.8.1/setup.cfg0000644000076500000240000000040213040732051016451 0ustar kislyukstaff00000000000000[bdist_rpm] provides = python-argcomplete doc_files = Authors.rst Changes.rst README.rst LICENSE.rst [bdist_wheel] universal = 1 [flake8] max-line-length = 120 ignore = E301, E302, E305, E401 exclude = my_shlex.py [egg_info] tag_build = tag_date = 0 argcomplete-1.8.1/setup.py0000755000076500000240000000334313040732011016350 0ustar kislyukstaff00000000000000#!/usr/bin/env python import glob from setuptools import setup, find_packages install_requires = [] tests_require = ["coverage", "flake8", "pexpect", "wheel"] try: import argparse # noqa except ImportError: install_requires.append('argparse') setup( name='argcomplete', version='1.8.1', url='https://github.com/kislyuk/argcomplete', license='Apache Software License', author='Andrey Kislyuk', author_email='kislyuk@gmail.com', description='Bash tab completion for argparse', long_description=open('README.rst').read(), install_requires=install_requires, tests_require=tests_require, extras_require={"test": tests_require}, packages=find_packages(exclude=['test']), scripts=glob.glob('scripts/*'), package_data={'argcomplete': ['bash_completion.d/python-argcomplete.sh']}, zip_safe=False, include_package_data=True, platforms=['MacOS X', 'Posix'], test_suite='test', classifiers=[ 'Environment :: Console', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Operating System :: MacOS :: MacOS X', 'Operating System :: POSIX', 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Development Status :: 5 - Production/Stable', 'Topic :: Software Development', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: System :: Shells', 'Topic :: Terminals' ] ) argcomplete-1.8.1/test/0000755000076500000240000000000013040732051015613 5ustar kislyukstaff00000000000000argcomplete-1.8.1/test/__init__.py0000644000076500000240000000000012730011252017710 0ustar kislyukstaff00000000000000argcomplete-1.8.1/test/__init__.pyc0000644000076500000240000000021312730537565020105 0ustar kislyukstaff00000000000000 `Wc@sdS(N((((s4/Users/kislyuk/projects/argcomplete/test/__init__.pytsargcomplete-1.8.1/test/prog0000755000076500000240000000215413040207436016516 0ustar kislyukstaff00000000000000#!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK """Test script used by test.TestBash.""" import argparse import argcomplete import os import sys def complete_cont(*args, **kwargs): return ['foo=', 'bar/', 'baz:'] def check_environ(*args, **kwargs): assert 'COMP_TYPE' in os.environ, 'wrapper should have set COMP_TYPE' assert len(sys.argv) == 1, 'should never be completed with arguments' return ['ok'] parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() subparsers.add_parser('basic').add_argument('arg', choices=['foo', 'bar', 'baz']) subparsers.add_parser('space').add_argument('arg', choices=['foo bar', 'baz']) subparsers.add_parser('cont').add_argument('arg').completer = complete_cont subparsers.add_parser('spec').add_argument('arg', choices=['d$e$f', 'd$e$g', 'x!x', r'y\y']) subparsers.add_parser('quote').add_argument('arg', choices=["1'1", '2"2']) subparsers.add_parser('break').add_argument('arg', choices=['a:b:c', 'a:b:d']) subparsers.add_parser('env').add_argument('arg').completer = check_environ argcomplete.autocomplete(parser) args = parser.parse_args() print(args.arg) argcomplete-1.8.1/test/test.py0000755000076500000240000012735613040731545017174 0ustar kislyukstaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, unicode_literals import os, sys, shutil, argparse, subprocess import pexpect, pexpect.replwrap from tempfile import TemporaryFile, mkdtemp TEST_DIR = os.path.abspath(os.path.dirname(__file__)) BASE_DIR = os.path.dirname(TEST_DIR) sys.path.insert(0, BASE_DIR) from argparse import ArgumentParser, SUPPRESS from argcomplete import ( autocomplete, CompletionFinder, split_line, ExclusiveCompletionFinder, ) from argcomplete.completers import FilesCompleter, DirectoriesCompleter from argcomplete.compat import USING_PYTHON2, str, sys_encoding, ensure_str, ensure_bytes if sys.version_info >= (2, 7): import unittest else: import unittest2 as unittest IFS = "\013" COMP_WORDBREAKS = " \t\n\"'><=;&(:" BASH_VERSION = subprocess.check_output(['bash', '-c', 'echo $BASH_VERSION']).decode() BASH_MAJOR_VERSION = int(BASH_VERSION.split('.')[0]) class TempDir(object): """ Temporary directory for testing FilesCompletion Usage: with TempDir(prefix="temp_fc") as t: print("tempdir", t) # you are not chdir-ed to the temporary directory # everything created here will be deleted """ def __init__(self, suffix="", prefix="tmpdir", dir=None): self.tmp_dir = mkdtemp(suffix=suffix, prefix=prefix, dir=dir) self.old_dir = os.getcwd() def __enter__(self): os.chdir(self.tmp_dir) return self.tmp_dir def __exit__(self, *err): os.chdir(self.old_dir) shutil.rmtree(self.tmp_dir) class TestArgcomplete(unittest.TestCase): def setUp(self): self._os_environ = os.environ os.environ = os.environ.copy() os.environ["_ARGCOMPLETE"] = "yes" os.environ["_ARC_DEBUG"] = "yes" os.environ["IFS"] = IFS os.environ["_ARGCOMPLETE_COMP_WORDBREAKS"] = COMP_WORDBREAKS def tearDown(self): os.environ = self._os_environ def run_completer(self, parser, command, point=None, completer=autocomplete, **kwargs): command = ensure_str(command) if point is None: # Adjust point for wide chars point = str(len(command.encode(sys_encoding))) with TemporaryFile() as t: os.environ["COMP_LINE"] = ensure_bytes(command) if USING_PYTHON2 else command os.environ["COMP_POINT"] = point self.assertRaises(SystemExit, completer, parser, output_stream=t, exit_method=sys.exit, **kwargs) t.seek(0) return t.read().decode(sys_encoding).split(IFS) def test_basic_completion(self): p = ArgumentParser() p.add_argument("--foo") p.add_argument("--bar") completions = self.run_completer(p, "prog ") self.assertEqual(set(completions), set(["-h", "--help", "--foo", "--bar"])) completions = self.run_completer(p, "prog -") self.assertEqual(set(completions), set(["-h", "--help", "--foo", "--bar"])) completions = self.run_completer(p, "prog ", always_complete_options=False) self.assertEqual(set(completions), set([""])) completions = self.run_completer(p, "prog -", always_complete_options=False) self.assertEqual(set(completions), set(["-h", "--help", "--foo", "--bar"])) def test_choices(self): def make_parser(): parser = ArgumentParser() parser.add_argument("--ship", choices=["submarine", b"speedboat"]) return parser expected_outputs = ( ("prog ", ["--ship", "-h", "--help"]), ("prog --shi", ["--ship "]), ("prog --ship ", ["submarine", "speedboat"]), ("prog --ship s", ["submarine", "speedboat"]), ("prog --ship su", ["submarine "]) ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_non_str_choices(self): def make_parser(): parser = ArgumentParser() parser.add_argument("x", type=int, choices=[4, 8, 15, 16, 23, 42]) return parser expected_outputs = ( ("prog ", ["4", "8", "15", "16", "23", "42", "-h", "--help"]), ("prog 1", ["15", "16"]), ("prog 2", ["23 "]), ("prog 4", ["4", "42"]), ("prog 4 ", ["-h", "--help"]) ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_suppress_args(self): def make_parser(): parser = ArgumentParser() parser.add_argument("--foo") parser.add_argument("--bar", help=SUPPRESS) return parser expected_outputs = ( ("prog ", ["--foo", "-h", "--help"]), ("prog --b", [""]) ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) expected_outputs = ( ("prog ", ["--foo", "--bar", "-h", "--help"]), ("prog --b", ["--bar "]) ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd, print_suppressed=True)), set(output)) def test_action_activation(self): def make_parser(): parser = ArgumentParser() parser.add_argument("var", choices=["bus", "car"]) parser.add_argument("value", choices=["orange", "apple"]) return parser expected_outputs = ( ("prog ", ["bus", "car", "-h", "--help"]), ("prog bu", ["bus "]), ("prog bus ", ["apple", "orange", "-h", "--help"]), ("prog bus appl", ["apple "]), ("prog bus apple ", ["-h", "--help"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_action_activation_with_subparser(self): def make_parser(): parser = ArgumentParser() parser.add_argument("name", nargs=2, choices=["a", "b", "c"]) subparsers = parser.add_subparsers(title="subcommands", metavar="subcommand") subparser_build = subparsers.add_parser("build") subparser_build.add_argument("var", choices=["bus", "car"]) subparser_build.add_argument("--profile", nargs=1) return parser expected_outputs = ( ("prog ", ["a", "b", "c", "-h", "--help"]), ("prog b", ["b "]), ("prog b ", ["a", "b", "c", "-h", "--help"]), ("prog c b ", ["build", "-h", "--help"]), ("prog c b bu", ["build "]), ("prog c b build ", ["bus", "car", "--profile", "-h", "--help"]), ("prog c b build ca", ["car "]), ("prog c b build car ", ["--profile", "-h", "--help"]), ("prog build car ", ["-h", "--help"]), ("prog a build car ", ["-h", "--help"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_completers(self): def c_url(prefix, parsed_args, **kwargs): return ["http://url1", "http://url2"] def make_parser(): parser = ArgumentParser() parser.add_argument("--url").completer = c_url parser.add_argument("--email", nargs=3, choices=["a@b.c", "a@b.d", "ab@c.d", "bcd@e.f", "bce@f.g"]) return parser expected_outputs = ( ("prog --url ", ["http://url1", "http://url2"]), ("prog --url \"", ['http://url1', 'http://url2']), ("prog --url \"http://url1\" --email ", ["a@b.c", "a@b.d", "ab@c.d", "bcd@e.f", "bce@f.g"]), ("prog --url \"http://url1\" --email a", ["a@b.c", "a@b.d", "ab@c.d"]), ("prog --url \"http://url1\" --email \"a@", ['a@b.c', 'a@b.d']), ("prog --url \"http://url1\" --email \"a@b.c\" \"a@b.d\" \"a@", ['a@b.c', 'a@b.d']), ("prog --url \"http://url1\" --email \"a@b.c\" \"a@b.d\" \"ab@c.d\" ", ["--url", "--email", "-h", "--help"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_subparser_completers(self): def c_depends_on_positional_arg1(prefix, parsed_args, **kwargs): return [parsed_args.arg1] def c_depends_on_optional_arg5(prefix, parsed_args, **kwargs): return [parsed_args.arg5] def make_parser(): parser = ArgumentParser() subparsers = parser.add_subparsers() subparser = subparsers.add_parser('subcommand') subparser.add_argument('arg1') subparser.add_argument('arg2').completer = c_depends_on_positional_arg1 subparser.add_argument('arg3').completer = c_depends_on_optional_arg5 subparser.add_argument('--arg4').completer = c_depends_on_optional_arg5 subparser.add_argument('--arg5') return parser expected_outputs = ( ("prog subcommand val1 ", ["val1", "--arg4", "--arg5", "-h", "--help"]), ("prog subcommand val1 val2 --arg5 val5 ", ["val5", "--arg4", "--arg5", "-h", "--help"]), ("prog subcommand val1 val2 --arg5 val6 --arg4 v", ["val6 "]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_file_completion(self): # setup and teardown should probably be in class with TempDir(prefix="test_dir_fc", dir="."): fc = FilesCompleter() os.makedirs(os.path.join("abcdefж", "klm")) self.assertEqual(fc("a"), ["abcdefж/"]) os.makedirs(os.path.join("abcaha", "klm")) with open("abcxyz", "w") as fp: fp.write("test") self.assertEqual(set(fc("a")), set(["abcdefж/", "abcaha/", "abcxyz"])) def test_filescompleter_filetype_integration(self): def make_parser(): parser = ArgumentParser() parser.add_argument('--r', type=argparse.FileType('r')) parser.add_argument('--w', type=argparse.FileType('w')) return parser with TempDir(prefix="test_dir_fc2", dir="."): os.makedirs(os.path.join("abcdefж", "klm")) os.makedirs(os.path.join("abcaha", "klm")) with open("abcxyz", "w") as fh, open("abcdefж/klm/test", "w") as fh2: fh.write("test") fh2.write("test") expected_outputs = ( ("prog subcommand --r ", ["abcxyz", "abcdefж/", "abcaha/"]), ("prog subcommand --w abcdefж/klm/t", ["abcdefж/klm/test "]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_directory_completion(self): completer = DirectoriesCompleter() def c(prefix): return set(completer(prefix)) with TempDir(prefix="test_dir", dir="."): # Create some temporary dirs and files (files must be ignored) os.makedirs(os.path.join("abc", "baz")) os.makedirs(os.path.join("abb", "baz")) os.makedirs(os.path.join("abc", "faz")) os.makedirs(os.path.join("def", "baz")) with open("abc1", "w") as fp1: with open("def1", "w") as fp2: fp1.write("A test") fp2.write("Another test") # Test completions self.assertEqual(c("a"), set(["abb/", "abc/"])) self.assertEqual(c("ab"), set(["abc/", "abb/"])) self.assertEqual(c("abc"), set(["abc/"])) self.assertEqual(c("abc/"), set(["abc/baz/", "abc/faz/"])) self.assertEqual(c("d"), set(["def/"])) self.assertEqual(c("def/"), set(["def/baz/"])) self.assertEqual(c("e"), set([])) self.assertEqual(c("def/k"), set([])) return def test_default_completer(self): def make_parser(): parser = ArgumentParser(add_help=False) parser.add_argument("--one") parser.add_argument("--many", nargs="+") return parser with TempDir(prefix="test_dir_dc", dir="."): os.mkdir("test") expected_outputs = ( ("prog --one ", ["test/"]), ("prog --many ", ["test/"]), ("prog --many test/ ", ["test/", "--one", "--many"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_subparsers(self): def make_parser(): parser = ArgumentParser() parser.add_argument("--age", type=int) sub = parser.add_subparsers() eggs = sub.add_parser("eggs") eggs.add_argument("type", choices=["on a boat", "with a goat", "in the rain", "on a train"]) spam = sub.add_parser("spam") spam.add_argument("type", choices=["ham", "iberico"]) return parser expected_outputs = ( ("prog ", ["--help", "eggs", "-h", "spam", "--age"]), ("prog --age 1 eggs", ["eggs "]), ("prog --age 2 eggs ", [r"on\ a\ train", r"with\ a\ goat", r"on\ a\ boat", r"in\ the\ rain", "--help", "-h"]), ("prog eggs ", [r"on\ a\ train", r"with\ a\ goat", r"on\ a\ boat", r"in\ the\ rain", "--help", "-h"]), ("prog eggs \"on a", ['on a train', 'on a boat']), ("prog eggs on\\ a", [r"on\ a\ train", "on\ a\ boat"]), ("prog spam ", ["iberico", "ham", "--help", "-h"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) self.assertEqual(set(self.run_completer(make_parser(), cmd, exclude=["-h"])), set(output) - set(["-h"])) self.assertEqual(set(self.run_completer(make_parser(), cmd, exclude=["-h", "--help"])), set(output) - set(["-h", "--help"])) def test_non_ascii(self): def make_parser(): _str = ensure_bytes if USING_PYTHON2 else str parser = ArgumentParser() # Python 2 argparse only works with byte strings or ascii unicode strings. # Python 3 argparse only works with unicode strings. parser.add_argument(_str("--книга"), choices=[ _str("Трудно быть богом"), _str("Парень из преисподней"), _str("Понедельник начинается в субботу"), ]) return parser expected_outputs = ( ("prog ", ["--книга", "-h", "--help"]), ("prog --книга ", [r"Трудно\ быть\ богом", r"Парень\ из\ преисподней", r"Понедельник\ начинается\ в\ субботу"]), ("prog --книга П", [r"Парень\ из\ преисподней", "Понедельник\ начинается\ в\ субботу"]), ("prog --книга Пу", [""]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_custom_validator(self): def make_parser(): parser = ArgumentParser() parser.add_argument("var", choices=["bus", "car"]) parser.add_argument("value", choices=["orange", "apple"]) return parser expected_outputs = ( ("prog ", ["-h", "--help"]), ("prog bu", [""]), ("prog bus ", ["-h", "--help"]), ("prog bus appl", [""]), ("prog bus apple ", ["-h", "--help"]), ) for cmd, output in expected_outputs: self.assertEqual( set(self.run_completer(make_parser(), cmd, validator=lambda x, y: False)), set(output) ) def test_different_validators(self): def make_parser(): parser = ArgumentParser() parser.add_argument("var", choices=["bus", "car"]) parser.add_argument("value", choices=["orange", "apple"]) return parser validators = ( lambda x, y: False, lambda x, y: True, lambda x, y: x.startswith(y), ) expected_outputs = ( ("prog ", ["-h", "--help"], validators[0]), ("prog ", ["bus", "car", "-h", "--help"], validators[1]), ("prog bu", ["bus "], validators[1]), ("prog bus ", ["apple", "orange", "-h", "--help"], validators[1]), ("prog bus appl", ["apple "], validators[2]), ("prog bus cappl", [""], validators[2]), ("prog bus pple ", ["-h", "--help"], validators[2]), ) for cmd, output, validator in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd, validator=validator)), set(output)) def test_readline_entry_point(self): def get_readline_completions(completer, text): completions = [] for i in range(9999): completion = completer.rl_complete(text, i) if completion is None: break completions.append(completion) return completions parser = ArgumentParser() parser.add_argument("rover", choices=["sojourner", "spirit", "opportunity", "curiosity"]) parser.add_argument("antenna", choices=["low gain", "high gain"]) completer = CompletionFinder(parser) self.assertEqual(get_readline_completions(completer, ""), ["-h", "--help", "sojourner", "spirit", "opportunity", "curiosity"]) self.assertEqual(get_readline_completions(completer, "s"), ["sojourner", "spirit"]) self.assertEqual(get_readline_completions(completer, "x"), []) def test_display_completions(self): parser = ArgumentParser() parser.add_argument("rover", choices=["sojourner", "spirit", "opportunity", "curiosity"], help="help for rover ") parser.add_argument("antenna", choices=["low gain", "high gain"], help="help for antenna") sub = parser.add_subparsers() p = sub.add_parser("list") p.add_argument("-o", "--oh", help="ttt") p.add_argument("-c", "--ch", help="ccc") sub2 = p.add_subparsers() sub2.add_parser("cat", help="list cat") sub2.add_parser("dog", help="list dog") completer = CompletionFinder(parser) completer.rl_complete("", 0) disp = completer.get_display_completions() self.assertEqual("help for rover ", disp.get("spirit", "")) self.assertEqual("help for rover ", disp.get("sojourner", "")) self.assertEqual("", disp.get("low gain", "")) completer.rl_complete('opportunity "low gain" list ', 0) disp = completer.get_display_completions() self.assertEqual("ttt", disp.get("-o --oh", "")) self.assertEqual("list cat", disp.get("cat", "")) completer.rl_complete("opportunity low\\ gain list --", 0) disp = completer.get_display_completions() self.assertEqual("ttt", disp.get("--oh", "")) self.assertEqual("ccc", disp.get("--ch", "")) def test_nargs_one_or_more(self): def make_parser(): parser = ArgumentParser() parser.add_argument("h1", choices=["c", "d"]) parser.add_argument("var", choices=["bus", "car"], nargs="+") parser.add_argument("value", choices=["orange", "apple"]) parser.add_argument("end", choices=["end"]) return parser expected_outputs = ( ("prog ", ["c", "d", "-h", "--help"]), ("prog c ", ["bus", "car", "-h", "--help"]), ("prog c bu", ["bus "]), ("prog c bus ", ["bus", "car", "apple", "orange", "-h", "--help"]), ("prog c bus car ", ["bus", "car", "apple", "orange", "-h", "--help"]), ("prog c bus appl", ["apple "]), # No way to know which completers to run past this point. ("prog c bus apple ", ["bus", "car", "apple", "orange", "end", "-h", "--help"]), ("prog c bus car apple ", ["bus", "car", "apple", "orange", "end", "-h", "--help"]), ("prog c bus car apple end ", ["bus", "car", "apple", "orange", "end", "-h", "--help"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_nargs_zero_or_more(self): def make_parser(): parser = ArgumentParser() # default="foo" is necessary to stop argparse trying to validate [] parser.add_argument("foo", choices=["foo"], nargs="*", default="foo") parser.add_argument("bar", choices=["bar"]) return parser expected_outputs = ( ("prog ", ["foo", "bar", "-h", "--help"]), ("prog foo ", ["foo", "bar", "-h", "--help"]), ("prog foo bar ", ["foo", "bar", "-h", "--help"]), ("prog foo foo bar ", ["foo", "bar", "-h", "--help"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_nargs_optional(self): def make_parser(): parser = ArgumentParser() parser.add_argument("foo", choices=["foo"], nargs="?") parser.add_argument("bar", choices=["bar"]) return parser expected_outputs = ( ("prog ", ["foo", "bar", "-h", "--help"]), ("prog foo ", ["foo", "bar", "-h", "--help"]), ("prog foo bar ", ["-h", "--help"]), ("prog bar ", ["foo", "bar", "-h", "--help"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_optional_nargs(self): def make_parser(): parser = ArgumentParser() parser.add_argument("--foo", choices=["foo1", "foo2"], nargs=2) parser.add_argument("--bar", choices=["bar1", "bar2"], nargs="?") parser.add_argument("--baz", choices=["baz1", "baz2"], nargs="*") parser.add_argument("--qux", choices=["qux1", "qux2"], nargs="+") parser.add_argument("--foobar", choices=["pos", "--opt"], nargs=argparse.REMAINDER) return parser options = ["--foo", "--bar", "--baz", "--qux", "--foobar", "-h", "--help"] expected_outputs = ( ("prog ", options), ("prog --foo ", ["foo1", "foo2"]), ("prog --foo foo1 ", ["foo1", "foo2"]), ("prog --foo foo1 foo2 ", options), ("prog --bar ", ["bar1", "bar2"] + options), ("prog --bar bar1 ", options), ("prog --baz ", ["baz1", "baz2"] + options), ("prog --baz baz1 ", ["baz1", "baz2"] + options), ("prog --qux ", ["qux1", "qux2"]), ("prog --qux qux1 ", ["qux1", "qux2"] + options), ("prog --foobar ", ["pos", "--opt"]), ("prog --foobar pos ", ["pos", "--opt"]), ("prog --foobar --", ["--opt "]), ("prog --foobar --opt ", ["pos", "--opt"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_positional_remainder(self): def make_parser(): parser = ArgumentParser() parser.add_argument("--foo", choices=["foo1", "foo2"]) parser.add_argument("remainder", choices=["pos", "--opt"], nargs=argparse.REMAINDER) return parser options = ["--foo", "-h", "--help"] expected_outputs = ( ("prog ", ["pos", "--opt"] + options), ("prog --foo foo1 ", ["pos", "--opt"] + options), ("prog pos ", ["pos", "--opt"]), ("prog -- ", ["pos", "--opt"]), ("prog -- --opt ", ["pos", "--opt"]) ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_skipped_completer(self): parser = ArgumentParser(add_help=False) parser.add_argument("--foo", choices=["--bar"]) self.assertEqual(self.run_completer(parser, "prog --foo --"), ["--foo "]) def test_optional_long_short_filtering(self): def make_parser(): parser = ArgumentParser() parser.add_argument("--foo") parser.add_argument("-b", "--bar") parser.add_argument("--baz", "--xyz") parser.add_argument("-t") parser.add_argument("-z", "--zzz") parser.add_argument("-x") return parser long_opts = "--foo --bar --baz --xyz --zzz --help -x -t".split() short_opts = "-b -t -x -z -h --foo --baz --xyz".split() expected_outputs = ( ("prog ", {"long": long_opts, "short": short_opts, True: long_opts + short_opts, False: [""]}), ("prog --foo", {"long": ["--foo "], "short": ["--foo "], True: ["--foo "], False: ["--foo "]}), ("prog --b", {"long": ["--bar", "--baz"], "short": ["--bar", "--baz"], True: ["--bar", "--baz"], False: ["--bar", "--baz"]}), ("prog -z -x", {"long": ["-x "], "short": ["-x "], True: ["-x "], False: ["-x "]}), ) for cmd, outputs in expected_outputs: for always_complete_options, output in outputs.items(): result = self.run_completer(make_parser(), cmd, always_complete_options=always_complete_options) self.assertEqual(set(result), set(output)) def test_exclusive(self): def make_parser(): parser = ArgumentParser(add_help=False) parser.add_argument("--foo", action="store_true") group = parser.add_mutually_exclusive_group() group.add_argument("--bar", action="store_true") group.add_argument("--no-bar", action="store_true") return parser expected_outputs = ( ("prog ", ["--foo", "--bar", "--no-bar"]), ("prog --foo ", ["--foo", "--bar", "--no-bar"]), ("prog --bar ", ["--foo", "--bar"]), ("prog --foo --no-bar ", ["--foo", "--no-bar"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_mixed_optional_positional(self): def make_parser(): parser = ArgumentParser(add_help=False) parser.add_argument("name", choices=["name1", "name2"]) group = parser.add_mutually_exclusive_group() group.add_argument("--get", action="store_true") group.add_argument("--set", action="store_true") return parser expected_outputs = ( ("prog ", ["--get", "--set", "name1", "name2"]), ("prog --", ["--get", "--set"]), ("prog --get ", ["--get", "name1", "name2"]), ("prog --get name1 ", ["--get "]) ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_append_space(self): def make_parser(): parser = ArgumentParser(add_help=False) parser.add_argument("foo", choices=["bar"]) return parser self.assertEqual(self.run_completer(make_parser(), "prog "), ["bar "]) self.assertEqual(self.run_completer(make_parser(), "prog ", append_space=False), ["bar"]) def test_exclusive_class(self): parser = ArgumentParser(add_help=False) parser.add_argument("--foo", dest="types", action="append_const", const=str) parser.add_argument("--bar", dest="types", action="append", choices=["bar1", "bar2"]) parser.add_argument("--baz", choices=["baz1", "baz2"]) parser.add_argument("--no-bar", action="store_true") completer = ExclusiveCompletionFinder(parser, always_complete_options=True) expected_outputs = ( ("prog ", ["--foo", "--bar", "--baz", "--no-bar"]), ("prog --baz ", ["baz1", "baz2"]), ("prog --baz baz1 ", ["--foo", "--bar", "--no-bar"]), ("prog --foo --no-bar ", ["--foo", "--bar", "--baz"]), ("prog --foo --bar bar1 ", ["--foo", "--bar", "--baz", "--no-bar"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(parser, cmd, completer=completer)), set(output)) def test_escape_special_chars(self): def make_parser(): parser = ArgumentParser(add_help=False) parser.add_argument("-1", choices=["bar<$>baz"]) parser.add_argument("-2", choices=[r"\* "]) parser.add_argument("-3", choices=["\"'"]) return parser self.assertEqual(set(self.run_completer(make_parser(), "prog -1 ")), {r"bar\<\$\>baz "}) self.assertEqual(set(self.run_completer(make_parser(), "prog -2 ")), {r"\\\*\ "}) self.assertEqual(set(self.run_completer(make_parser(), "prog -3 ")), {r"\"\' "}) self.assertEqual(set(self.run_completer(make_parser(), 'prog -3 "')), {r"\"'"}) self.assertEqual(set(self.run_completer(make_parser(), "prog -3 '")), {"\"'\\''"}) os.environ["_ARGCOMPLETE_SHELL"] = "tcsh" self.assertEqual(set(self.run_completer(make_parser(), "prog -1 ")), {"bar<$>baz "}) # The trailing space won't actually work correctly in tcsh. self.assertEqual(set(self.run_completer(make_parser(), "prog -2 ")), {r"\* "}) self.assertEqual(set(self.run_completer(make_parser(), "prog -3 ")), {"\"' "}) self.assertEqual(set(self.run_completer(make_parser(), 'prog -3 "')), {"\"'"}) self.assertEqual(set(self.run_completer(make_parser(), "prog -3 '")), {"\"'"}) class TestArgcompleteREPL(unittest.TestCase): def setUp(self): pass def tearDown(self): pass def run_completer(self, parser, completer, command, point=None, **kwargs): cword_prequote, cword_prefix, cword_suffix, comp_words, first_colon_pos = split_line(command) completions = completer._get_completions( comp_words, cword_prefix, cword_prequote, first_colon_pos) return completions def test_repl_multiple_complete(self): p = ArgumentParser() p.add_argument("--foo") p.add_argument("--bar") c = CompletionFinder(p, always_complete_options=True) completions = self.run_completer(p, c, "prog ") assert(set(completions) == set(["-h", "--help", "--foo", "--bar"])) completions = self.run_completer(p, c, "prog --") assert(set(completions) == set(["--help", "--foo", "--bar"])) def test_repl_parse_after_complete(self): p = ArgumentParser() p.add_argument("--foo", required=True) p.add_argument("bar", choices=["bar"]) c = CompletionFinder(p, always_complete_options=True) completions = self.run_completer(p, c, "prog ") assert(set(completions) == set(["-h", "--help", "--foo", "bar"])) args = p.parse_args(["--foo", "spam", "bar"]) assert(args.foo == "spam") assert(args.bar == "bar") # Both options are required - check the parser still enforces this. with self.assertRaises(SystemExit): p.parse_args(["--foo", "spam"]) with self.assertRaises(SystemExit): p.parse_args(["bar"]) def test_repl_subparser_parse_after_complete(self): p = ArgumentParser() sp = p.add_subparsers().add_parser("foo") sp.add_argument("bar", choices=["bar"]) c = CompletionFinder(p, always_complete_options=True) completions = self.run_completer(p, c, "prog foo ") assert(set(completions) == set(["-h", "--help", "bar"])) args = p.parse_args(["foo", "bar"]) assert(args.bar == "bar") # "bar" is required - check the parser still enforces this. with self.assertRaises(SystemExit): p.parse_args(["foo"]) def test_repl_subcommand(self): p = ArgumentParser() p.add_argument("--foo") p.add_argument("--bar") s = p.add_subparsers() s.add_parser("list") s.add_parser("set") show = s.add_parser("show") def abc(): pass show.add_argument("--test") ss = show.add_subparsers() de = ss.add_parser("depth") de.set_defaults(func=abc) c = CompletionFinder(p, always_complete_options=True) expected_outputs = ( ("prog ", ["-h", "--help", "--foo", "--bar", "list", "show", "set"]), ("prog li", ["list "]), ("prog s", ["show", "set"]), ("prog show ", ["--test", "depth", "-h", "--help"]), ("prog show d", ["depth "]), ("prog show depth ", ["-h", "--help"]), ) for cmd, output in expected_outputs: self.assertEqual(set(self.run_completer(p, c, cmd)), set(output)) def test_repl_reuse_parser_with_positional(self): p = ArgumentParser() p.add_argument("foo", choices=["aa", "bb", "cc"]) p.add_argument("bar", choices=["d", "e"]) c = CompletionFinder(p, always_complete_options=True) self.assertEqual(set(self.run_completer(p, c, "prog ")), set(["-h", "--help", "aa", "bb", "cc"])) self.assertEqual(set(self.run_completer(p, c, "prog aa ")), set(["-h", "--help", "d", "e"])) self.assertEqual(set(self.run_completer(p, c, "prog ")), set(["-h", "--help", "aa", "bb", "cc"])) class TestSplitLine(unittest.TestCase): def setUp(self): self._os_environ = os.environ os.environ = os.environ.copy() os.environ['_ARGCOMPLETE_COMP_WORDBREAKS'] = COMP_WORDBREAKS def tearDown(self): os.environ = self._os_environ def prefix(self, line): return split_line(line)[1] def wordbreak(self, line): return split_line(line)[4] def test_simple(self): self.assertEqual(self.prefix('a b c'), 'c') def test_escaped_special(self): self.assertEqual(self.prefix('a\$b'), 'a$b') self.assertEqual(self.prefix('a\`b'), 'a`b') def test_unescaped_special(self): self.assertEqual(self.prefix('a$b'), 'a$b') self.assertEqual(self.prefix('a`b'), 'a`b') @unittest.expectedFailure def test_escaped_special_in_double_quotes(self): self.assertEqual(self.prefix('"a\$b'), 'a$b') self.assertEqual(self.prefix('"a\`b'), 'a`b') def test_punctuation(self): self.assertEqual(self.prefix('a,'), 'a,') def test_last_wordbreak_pos(self): self.assertEqual(self.wordbreak('a'), None) self.assertEqual(self.wordbreak('a b:c'), 1) self.assertEqual(self.wordbreak('a b:c=d'), 3) self.assertEqual(self.wordbreak('a b:c=d '), None) self.assertEqual(self.wordbreak('a b:c=d e'), None) self.assertEqual(self.wordbreak('"b:c'), None) self.assertEqual(self.wordbreak('"b:c=d'), None) self.assertEqual(self.wordbreak('"b:c=d"'), None) self.assertEqual(self.wordbreak('"b:c=d" '), None) class _TestSh(object): """ Contains tests which should work in any shell using argcomplete. Tests use the test program in this directory named ``prog``. All commands are expected to input one of the valid choices which is then printed and collected by the shell wrapper. Any tabs in the input line simulate the user pressing tab. For example, ``self.sh.run_command('prog basic "b\tr\t')`` will simulate having the user: 1. Type ``prog basic "b`` 2. Push tab, which returns ``['bar', 'baz']``, filling in ``a`` 3. Type ``r`` 4. Push tab, which returns ``['bar']``, filling in ``" `` 5. Push enter, submitting ``prog basic "bar" `` The end result should be ``bar`` being printed to the screen. """ sh = None expected_failures = [] @classmethod def setUpClass(cls, *args, **kwargs): for name in cls.expected_failures: test = getattr(cls, name) @unittest.expectedFailure def wrapped(self, test=test): test(self) setattr(cls, name, wrapped) super(_TestSh, cls).setUpClass(*args, **kwargs) def setUp(self): raise NotImplementedError def tearDown(self): with self.assertRaises(pexpect.EOF): self.sh.run_command('exit') def test_simple_completion(self): self.assertEqual(self.sh.run_command('prog basic f\t'), 'foo\r\n') def test_partial_completion(self): self.assertEqual(self.sh.run_command('prog basic b\tr'), 'bar\r\n') def test_single_quoted_completion(self): self.assertEqual(self.sh.run_command("prog basic 'f\t"), 'foo\r\n') def test_double_quoted_completion(self): self.assertEqual(self.sh.run_command('prog basic "f\t'), 'foo\r\n') def test_unquoted_space(self): self.assertEqual(self.sh.run_command('prog space f\t'), 'foo bar\r\n') def test_quoted_space(self): self.assertEqual(self.sh.run_command('prog space "f\t'), 'foo bar\r\n') def test_continuation(self): # This produces 'prog basic foo --', and '--' is ignored. self.assertEqual(self.sh.run_command('prog basic f\t--'), 'foo\r\n') # These do not insert a space, so the '--' is part of the token. self.assertEqual(self.sh.run_command('prog cont f\t--'), 'foo=--\r\n') self.assertEqual(self.sh.run_command('prog cont bar\t--'), 'bar/--\r\n') self.assertEqual(self.sh.run_command('prog cont baz\t--'), 'baz:--\r\n') def test_quoted_exact(self): self.assertEqual(self.sh.run_command('prog basic "f\t--'), 'foo\r\n') def test_special_characters(self): self.assertEqual(self.sh.run_command('prog spec d\tf'), 'd$e$f\r\n') self.assertEqual(self.sh.run_command('prog spec x\t'), 'x!x\r\n') self.assertEqual(self.sh.run_command('prog spec y\t'), 'y\\y\r\n') def test_special_characters_single_quoted(self): self.assertEqual(self.sh.run_command("prog spec 'd\tf'"), 'd$e$f\r\n') def test_special_characters_double_quoted(self): self.assertEqual(self.sh.run_command('prog spec "d\tf"'), 'd$e$f\r\n') def test_parse_special_characters(self): self.assertEqual(self.sh.run_command('prog spec d$e$\tf'), 'd$e$f\r\n') self.assertEqual(self.sh.run_command('prog spec d$e\tf'), 'd$e$f\r\n') self.assertEqual(self.sh.run_command("prog spec 'd$e\tf\t"), 'd$e$f\r\n') def test_parse_special_characters_dollar(self): # First tab expands to 'd\$e\$'; completion works with 'd$' but not 'd\$'. self.assertEqual(self.sh.run_command('prog spec "d$e\tf\t'), 'd$e$f\r\n') def test_exclamation_in_double_quotes(self): # Exclamation marks cannot be properly escaped within double quotes. # 'a!b' == "a"\!"b" self.assertEqual(self.sh.run_command('prog spec "x\t'), 'x!x\r\n') def test_quotes(self): self.assertEqual(self.sh.run_command('prog quote 1\t'), "1'1\r\n") self.assertEqual(self.sh.run_command('prog quote 2\t'), '2"2\r\n') def test_single_quotes_in_double_quotes(self): self.assertEqual(self.sh.run_command('prog quote "1\t'), "1'1\r\n") def test_single_quotes_in_single_quotes(self): # Single quotes cannot be escaped within single quotes. # "a'b" == 'a'\''b' self.assertEqual(self.sh.run_command("prog quote '1\t"), "1'1\r\n") def test_wordbreak_chars(self): self.assertEqual(self.sh.run_command('prog break a\tc'), 'a:b:c\r\n') self.assertEqual(self.sh.run_command('prog break a:b:\tc'), 'a:b:c\r\n') self.assertEqual(self.sh.run_command('prog break a:b\tc'), 'a:b:c\r\n') self.assertEqual(self.sh.run_command("prog break 'a\tc'"), 'a:b:c\r\n') self.assertEqual(self.sh.run_command("prog break 'a:b\tc\t"), 'a:b:c\r\n') self.assertEqual(self.sh.run_command('prog break "a\tc"'), 'a:b:c\r\n') self.assertEqual(self.sh.run_command('prog break "a:b\tc\t'), 'a:b:c\r\n') def test_completion_environment(self): self.assertEqual(self.sh.run_command('prog env o\t'), 'ok\r\n') class TestBash(_TestSh, unittest.TestCase): expected_failures = [ 'test_parse_special_characters_dollar', 'test_exclamation_in_double_quotes', ] if BASH_MAJOR_VERSION < 4: # This requires compopt which is not available in 3.x. expected_failures.append('test_quoted_exact') install_cmd = 'eval "$(register-python-argcomplete prog)"' def setUp(self): sh = pexpect.replwrap.bash() path = ':'.join([os.path.join(BASE_DIR, 'scripts'), TEST_DIR, '$PATH']) sh.run_command('export PATH={0}'.format(path)) sh.run_command('export PYTHONPATH={0}'.format(BASE_DIR)) output = sh.run_command(self.install_cmd) self.assertEqual(output, '') self.sh = sh def test_one_space_after_exact(self): """Test exactly one space is appended after an exact match.""" # Actual command run is 'echo "prog basic foo "'. result = self.sh.run_command('prog basic f\t"\1echo "') self.assertEqual(result, 'prog basic foo \r\n') @unittest.skipIf(BASH_MAJOR_VERSION < 4, 'complete -D not supported') class TestBashGlobal(TestBash): install_cmd = 'eval "$(activate-global-python-argcomplete --dest=-)"' def test_python_completion(self): self.sh.run_command('cd ' + TEST_DIR) self.assertEqual(self.sh.run_command('python ./prog basic f\t'), 'foo\r\n') def test_python_filename_completion(self): self.sh.run_command('cd ' + TEST_DIR) self.assertEqual(self.sh.run_command('python ./pro\tbasic f\t'), 'foo\r\n') def test_python_not_executable(self): """Test completing a script that cannot be run directly.""" prog = os.path.join(TEST_DIR, 'prog') with TempDir(prefix='test_dir_py', dir='.'): shutil.copy(prog, '.') self.sh.run_command('cd ' + os.getcwd()) self.sh.run_command('chmod -x ./prog') self.assertIn('Permission denied', self.sh.run_command('./prog')) self.assertEqual(self.sh.run_command('python ./prog basic f\t'), 'foo\r\n') class TestTcsh(_TestSh, unittest.TestCase): expected_failures = [ 'test_unquoted_space', 'test_quoted_space', 'test_continuation', 'test_parse_special_characters', 'test_parse_special_characters_dollar', ] def setUp(self): sh = Shell('tcsh') path = ' '.join([os.path.join(BASE_DIR, 'scripts'), TEST_DIR, '$path']) sh.run_command('set path = ({0})'.format(path)) sh.run_command('setenv PYTHONPATH {0}'.format(BASE_DIR)) output = sh.run_command('eval `register-python-argcomplete --shell tcsh prog`') self.assertEqual(output, '') self.sh = sh def tearDown(self): # The shell wrapper is fragile; exactly which exception is raised # differs depending on environment. with self.assertRaises((pexpect.EOF, OSError)): self.sh.run_command('exit') self.sh.run_command('') class Shell(object): def __init__(self, shell): self.child = pexpect.spawn(shell, encoding='utf-8') def run_command(self, command): try: self.child.sendline(r"echo -n \#\#\#; {0}; echo -n \#\#\#".format(command)) self.child.expect_exact('###', timeout=1) self.child.expect_exact('###', timeout=1) return self.child.before finally: # Send Ctrl+C in case we get stuck. self.child.sendline('\x03') if __name__ == "__main__": unittest.main() argcomplete-1.8.1/test/test.pyc0000644000076500000240000007552213000565113017321 0ustar kislyukstaff00000000000000 fWc@`sddlmZmZmZmZddlZddlZddlZddlZddl m Z m Z ej j dej jej jej jedddlmZmZddlmZmZmZddlmZmZddlmZmZmZmZm Z ej!d d fkr6ddl"Z"n ddl#Z"d Z$d e%fd YZ&de"j'fdYZ(de"j'fdYZ)e*dkre"j+ndS(i(tabsolute_importtdivisiontprint_functiontunicode_literalsN(t TemporaryFiletmkdtempu..(tArgumentParsertSUPPRESS(t autocompletetCompletionFindert split_line(tFilesCompletertDirectoriesCompleter(t USING_PYTHON2tstrt sys_encodingt ensure_strt ensure_bytesiiu tTempDircB`s2eZdZddddZdZdZRS(u Temporary directory for testing FilesCompletion Usage: with TempDir(prefix="temp_fc") as t: print("tempdir", t) # you are not chdir-ed to the temporary directory # everything created here will be deleted uutmpdircC`s1td|d|d||_tj|_dS(Ntsuffixtprefixtdir(Rttmp_dirtostgetcwdtold_dir(tselfRRR((s0/Users/kislyuk/projects/argcomplete/test/test.pyt__init__'scC`stj|j|jS(N(RtchdirR(R((s0/Users/kislyuk/projects/argcomplete/test/test.pyt __enter__+scG`s$tj|jtj|jdS(N(RRRtshutiltrmtreeR(Rterr((s0/Users/kislyuk/projects/argcomplete/test/test.pyt__exit__/sN(t__name__t __module__t__doc__tNoneRRR!(((s0/Users/kislyuk/projects/argcomplete/test/test.pyRs  tTestArgcompletecB`seZdZdZddZdZdZdZdZ dZ dZ d Z d Z d Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZRS(cC`s+dtjd<=;|&(:u_ARGCOMPLETE_COMP_WORDBREAKSt output_streamt exit_methodi(RR%RtlentencodeRRR RRR't assertRaisest SystemExitRtsystexittseektreadtdecodetsplitR((Rtparsertcommandtpointtkwargstt((s0/Users/kislyuk/projects/argcomplete/test/test.pyt run_completer=s       cC`st}|jd|jd|j|d}|jt|tddddg|j|d}|jt|tddddg|j|ddt}|jt|tdg|j|ddt}|jt|tddddgdS( Nu--foou--baruprog u-hu--helpuprog -talways_complete_optionsu(Rt add_argumentR<t assertEqualstsettFalse(Rtpt completions((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_basic_completionKs   ((cC`sd}ddddgfddgfdd d gfd d d gfd d gff}x?|D]7\}}|jt|j||t|q^WdS(NcS`s&t}|jddddg|S(Nu--shiptchoicesu submarinet speedboat(RR>(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyt make_parser]s uprog u--shipu-hu--helpu prog --shiu--ship u prog --ship u submarineu speedboatu prog --ship suprog --ship suu submarine (t assertEqualR@R<(RRGtexpected_outputstcmdtoutput((s0/Users/kislyuk/projects/argcomplete/test/test.pyt test_choices\s  c C`sd}dddddddd d gfd ddgfd d gfdddgfdd d gff}x?|D]7\}}|jt|j||t|qpWdS(Nc S`s8t}|jddtddddddd g|S( NuxttypeREiiiiii*(RR>tint(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGns +uprog u4u8u15u16u23u42u-hu--helpuprog 1uprog 2u23 uprog 4uprog 4 (RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_non_str_choicesms ! cC`sd}ddddgfddgff}x?|D]7\}}|jt|j||t|q4Wdddddgfdd gff}xE|D]=\}}|jt|j||d tt|qWdS( NcS`s-t}|jd|jddt|S(Nu--foou--barthelp(RR>R(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs  uprog u--foou-hu--helpuprog --buu--baru--bar tprint_suppressed(RHR@R<tTrue(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_suppress_args~s /cC`sd}dddddgfddgfd d d ddgfd d gfdddgff}x?|D]7\}}|jt|j||t|qgWdS(NcS`s?t}|jddddg|jddddg|S(NuvarREubusucaruvalueuorangeuapple(RR>(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs uprog ubusucaru-hu--helpuprog buubus u prog bus uappleuorangeu prog bus appluapple uprog bus apple (RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_action_activations   c C`sd}ddddddgfdd gfd dddddgfd d ddgfd dgfddddddgfddgfddddgfdddgfdddgff }x?|D]7\}}|jt|j||t|qWdS(NcS`st}|jdddddddg|jdd d d }|jd }|jd dddg|jddd|S(NunametnargsiREuaubucttitleu subcommandstmetavaru subcommandubuilduvarubusucaru --profilei(RR>tadd_subparserst add_parser(R7t subparserstsubparser_build((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs "uprog uaubucu-hu--helpuprog bub uprog b u prog c b ubuildu prog c b buubuild uprog c b build ubusucaru --profileuprog c b build caucar uprog c b build car uprog build car uprog a build car (RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyt%test_action_activation_with_subparsers    c `sdfd}dddgfdddgfd d d d d dgfdd d d gfdddgfdddgfdddddgff}x?|D]7\}}|jt|j||t|qWdS(Nc[`s ddgS(Nu http://url1u http://url2((Rt parsed_argsR:((s0/Users/kislyuk/projects/argcomplete/test/test.pytc_urlsc `sGt}|jd_|jdddddddd d g|S( Nu--urlu--emailRUiREua@b.cua@b.duab@c.dubcd@e.fubce@f.g(RR>t completer(R7(R^(s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs (u prog --url u http\://url1u http\://url2u prog --url "u "http://url1u "http://url2u!prog --url "http://url1" --email ua\@b.cua\@b.duab\@c.dubcd\@e.fubce\@f.gu"prog --url "http://url1" --email au$prog --url "http://url1" --email "a@u"a@b.cu"a@b.du4prog --url "http://url1" --email "a@b.c" "a@b.d" "a@u:prog --url "http://url1" --email "a@b.c" "a@b.d" "ab@c.d" u--urlu--emailu-hu--help(RHR@R<(RRGRIRJRK((R^s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_completerss c`sddfd}dddddd gfd d dddd gfd d gff}x?|D]7\}}|jt|j||t|qmWdS(Nc[`s |jgS(N(targ1(RR]R:((s0/Users/kislyuk/projects/argcomplete/test/test.pytc_depends_on_positional_arg1sc[`s |jgS(N(targ5(RR]R:((s0/Users/kislyuk/projects/argcomplete/test/test.pytc_depends_on_optional_arg5sc`sxt}|j}|jd}|jd|jd_|jd_|jd_|jd|S(Nu subcommanduarg1uarg2uarg3u--arg4u--arg5(RRXRYR>R_(R7RZt subparser(RdRb(s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs    uprog subcommand val1 uval1u--arg4u--arg5u-hu--helpu&prog subcommand val1 val2 --arg5 val5 uval5u.prog subcommand val1 val2 --arg5 val6 --arg4 vuval6 (RHR@R<(RRGRIRJRK((RdRbs0/Users/kislyuk/projects/argcomplete/test/test.pyttest_subparser_completerss   c C`stddddt}tjtjjdd|j|ddgtjtjjd dtd d }|jd WdQX|jt |dt dd d gWdQXdS(NRu test_dir_fcRu.uabcdefжuklmuau abcdefж/uabcahauabcxyzuwutestuabcaha/( RR RtmakedirstpathtjoinRHtopentwriteR@(Rtfctfp((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_file_completions cC`sd}tddddtjtjjddtjtjjddtd d 9}td d !}|jd |jd WdQXWdQXd d ddgfddgff}x?|D]7\}}|jt|j ||t|qWWdQXdS(NcS`sEt}|jddtjd|jddtjd|S(Nu--rRMuru--wuw(RR>targparsetFileType(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs Ru test_dir_fc2Ru.uabcdefжuklmuabcahauabcxyzuwuabcdefж/klm/testutestuprog subcommand --r u abcdefж/uabcaha/u"prog subcommand --w abcdefж/klm/tuabcdefж/klm/test ( RRRgRhRiRjRkRHR@R<(RRGtfhtfh2RIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyt(test_filescompleter_filetype_integrations  c`stfd}tddddtjtjjddtjtjjddtjtjjdd tjtjjd dtd d 9}td d !}|jd|jdWdQXWdQX|j|dt ddg|j|dt ddg|j|dt dg|j|dt ddg|j|dt dg|j|dt dg|j|dt g|j|dt gWdQXdS(Nc`st|S(N(R@(R(R_(s0/Users/kislyuk/projects/argcomplete/test/test.pytcsRutest_dirRu.uabcubazuabbufazudefuabc1uwudef1uA testu Another testuauabb/uabc/uabuabc/baz/uabc/faz/ududef/udef/baz/ueudef/k( R RRRgRhRiRjRkRHR@(RRttfp1tfp2((R_s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_directory_completions(  """"c C`sjd}ddddddgfdd gfd d d d dddgfdd d d dddgfdddgfdd d gfdddddgff}x|D]\}}|jt|j||t||jt|j||ddgt|tdg|jt|j||dddgt|tddgqWdS(NcS`st}|jddt|j}|jd}|jdddddd g|jd }|jddd d g|S( Nu--ageRMueggsutypeREu on a boatu with a goatu in the rainu on a trainuspamuhamuiberico(RR>RNRXRY(R7tsubteggstspam((s0/Users/kislyuk/projects/argcomplete/test/test.pyRG.s  uprog u--helpueggsu-huspamu--ageuprog --age 1 eggsueggs uprog --age 2 eggs u on a trainu with a goatu on a boatu in the rainu prog eggs uprog eggs "on au "on a trainu "on a boatuprog eggs on\ au prog spam uibericouhamtexclude(RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_subparsers-s  +A*cC`sd}ddddgfdddd gfd dd gfd d gff}x?|D]7\}}|jt|j||t|qUWdS( NcS`sStr tnt}t}|j|dd|d|d|dg|S(Nu --книгаREu Трудно быть богомu(Парень из преисподнейu=Понедельник начинается в субботу(R RRRR>(t_strR7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGIs   uprog u --книгаu-hu--helpuprog --книга u Трудно быть богомu(Парень из преисподнейu=Понедельник начинается в субботуuprog --книга Пuprog --книга Пуu(RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_non_asciiHs cC`sd}dddgfddgfdddgfddgfd ddgff}xH|D]@\}}|jt|j||d d t|q[WdS( NcS`s?t}|jddddg|jddddg|S(NuvarREubusucaruvalueuorangeuapple(RR>(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGas uprog u-hu--helpuprog buuu prog bus u prog bus appluprog bus apple t validatorcS`stS(N(RA(txty((s0/Users/kislyuk/projects/argcomplete/test/test.pytqs(RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_custom_validator`s   !c C`sd}dddf}dddg|dfdd d ddg|d fd d g|d fdddddg|d fddg|dfddg|dfdddg|dff}xH|D]@\}}}|jt|j||d|t|qWdS(NcS`s?t}|jddddg|jddddg|S(NuvarREubusucaruvalueuorangeuapple(RR>(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGvs cS`stS(N(RA(RR((s0/Users/kislyuk/projects/argcomplete/test/test.pyR}scS`stS(N(RR(RR((s0/Users/kislyuk/projects/argcomplete/test/test.pyR~scS`s |j|S(N(t startswith(RR((s0/Users/kislyuk/projects/argcomplete/test/test.pyRsuprog u-hu--helpiubusucariuprog buubus u prog bus uappleuorangeu prog bus appluapple iuprog bus cappluuprog bus pple R(RHR@R<(RRGt validatorsRIRJRKR((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_different_validatorsus  cC`sd}t}|jddddddg|jddd d gt|}|j||d d d ddddg|j||dddg|j||dgdS(NcS`sPg}xCtdD]5}|j||}|dkr;Pn|j|qW|S(Ni'(tranget rl_completeR%tappend(R_ttextRCtit completion((s0/Users/kislyuk/projects/argcomplete/test/test.pytget_readline_completionss uroverREu sojourneruspiritu opportunityu curiosityuantennaulow gainu high gainuu-hu--helpusux(RR>R RH(RRR7R_((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_readline_entry_points  cC`st}|jddddddgdd|jd dd d gdd |j}|jd }|jdddd|jdddd|j}|jddd|jdddt|}|jdd|j}|jd|jdd|jd|jdd|jd|jd d|jdd|j}|jd|jdd|jd|jdd|jdd|j}|jd|jdd|jd|jdddS(NuroverREu sojourneruspiritu opportunityu curiosityRPuhelp for rover uantennaulow gainu high gainuhelp for antennaulistu-ou--ohutttu-cu--chucccucatulist catudogulist doguiuopportunity "low gain" list u-o --ohuopportunity low\ gain list --( RR>RXRYR Rtget_display_completionsRHtget(RR7RxRBtsub2R_tdisp((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_display_completionss4        cC`s'd}dddddgfddd ddgfd d gfd dd d dddgfddd d dddgfddgfddd d ddddgfddd d ddddgfddd d ddddgff }x?|D]7\}}|jt|j||t|qWdS(NcS`stt}|jddddg|jddddgdd |jd dd d g|jd dd g|S(Nuh1REucuduvarubusucarRUu+uvalueuorangeuappleuend(RR>(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs  uprog ucudu-hu--helpuprog c ubusucaru prog c buubus u prog c bus uappleuorangeuprog c bus car uprog c bus appluapple uprog c bus apple uenduprog c bus car apple uprog c bus car apple end (RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_nargs_one_or_mores   $cC`sd}dddddgfdddddgfdddddgfd ddddgff}x?|D]7\}}|jt|j||t|qjWdS( NcS`sEt}|jdddgdddd|jdddg|S(NufooRERUu*tdefaultubar(RR>(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs "uprog ufooubaru-hu--helpu prog foo u prog foo bar uprog foo foo bar (RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_nargs_zero_or_mores cC`sd}dddddgfdddddgfdddgfd ddddgff}x?|D]7\}}|jt|j||t|qdWdS( NcS`s?t}|jdddgdd|jdddg|S(NufooRERUu?ubar(RR>(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs uprog ufooubaru-hu--helpu prog foo u prog foo bar u prog bar (RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_nargs_optionals cC`s=d}dddddddg}d |fd d d gfd d d gfd|fdddg|fd|fdddg|fdddg|fdddgfdddg|fdddgfdddgfdd gfd!ddgff}x?|D]7\}}|jt|j||t|qWdS("NcS`st}|jddddgdd|jdddd gdd |jd dd d gdd|jddddgdd|jddddgdtj|S(Nu--fooREufoo1ufoo2RUiu--barubar1ubar2u?u--bazubaz1ubaz2u*u--quxuqux1uqux2u+u--foobaruposu--opt(RR>Rot REMAINDER(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGs "u--foou--baru--bazu--quxu--foobaru-hu--helpuprog u prog --foo ufoo1ufoo2uprog --foo foo1 uprog --foo foo1 foo2 u prog --bar ubar1ubar2uprog --bar bar1 u prog --baz ubaz1ubaz2uprog --baz baz1 u prog --qux uqux1uqux2uprog --qux qux1 uprog --foobar uposu--optuprog --foobar pos uprog --foobar --u--opt uprog --foobar --opt (RHR@R<(RRGtoptionsRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_optional_nargss$     cC`sd}dddg}dddg|fdddg|fd ddgfd ddgfd ddgff}x?|D]7\}}|jt|j||t|qxWdS( NcS`sHt}|jddddg|jddddgdtj|S( Nu--fooREufoo1ufoo2u remainderuposu--optRU(RR>RoR(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRG$s "u--foou-hu--helpuprog uposu--optuprog --foo foo1 u prog pos uprog -- uprog -- --opt (RHR@R<(RRGRRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_positional_remainder#s cC`sHtdt}|jdddg|j|j|ddgdS(Ntadd_helpu--fooREu--baru prog --foo --u--foo (RRAR>RHR<(RR7((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_skipped_completer7sc C`sad}dj}dj}di|d6|d6||t6dgt6fdid gd6d gd6d gt6d gt6fd id d gd6d d gd6d d gt6d d gt6fd idgd6dgd6dgt6dgt6ff}xh|D]`\}}xQ|jD]C\}}|j||d|} |jt| t|qWqWdS(NcS`sdt}|jd|jdd|jdd|jd|jdd|jd |S( Nu--foou-bu--baru--bazu--xyzu-tu-zu--zzzu-x(RR>(R7((s0/Users/kislyuk/projects/argcomplete/test/test.pyRG=s    u*--foo --bar --baz --xyz --zzz --help -x -tu -b -t -x -z -h --foo --baz --xyzuprog ulongushortuu prog --foou--foo uprog --bu--baru--bazu prog -z -xu-x R=(R6RRRAtitemsR<RHR@( RRGt long_optst short_optsRIRJtoutputsR=RKtresult((s0/Users/kislyuk/projects/argcomplete/test/test.pyt"test_optional_long_short_filtering<s  ,1=7cC`sd}ddddgfddddgfdddgfdddgff}x?|D]7\}}|jt|j||t|qXWdS( NcS`sXtdt}|jddd|j}|jddd|jddd|S(NRu--footactionu store_trueu--baru--no-bar(RRAR>tadd_mutually_exclusive_group(R7tgroup((s0/Users/kislyuk/projects/argcomplete/test/test.pyRGUs  uprog u--foou--baru--no-baru prog --foo u prog --bar uprog --foo --no-bar (RHR@R<(RRGRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_exclusiveTs N(R"R#R)R*R%R<RDRLRORSRTR\R`RfRnRsRwR|R~RRRRRRRRRRRR(((s0/Users/kislyuk/projects/argcomplete/test/test.pyR&4s8                      %   tTestArgcompleteREPLcB`sSeZdZdZddZdZdZdZe j dZ RS(cC`sdS(N((R((s0/Users/kislyuk/projects/argcomplete/test/test.pyR)iscC`sdS(N((R((s0/Users/kislyuk/projects/argcomplete/test/test.pyR*lsc K`sNt|\}}}} } | jdtjd|j| ||| } | S(Ni(R tinsertR1targvt_get_completions( RR7R_R8R9R:tcword_prequotet cword_prefixt cword_suffixt comp_wordstfirst_colon_posRC((s0/Users/kislyuk/projects/argcomplete/test/test.pyR<os cC`st}|jd|jdt|dt}|j||d}t|tddddgkstt|j||d}t|tdddgkstdS(Nu--foou--barR=uprog u-hu--helpuprog --(RR>R RRR<R@tAssertionError(RRBRtRC((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_repl_multiple_completeys   *cC`st}|jd|jdt|dt}|j||d}t|tddddgkstt|jddg}|jdkstdS(Nu--foou--barR=uprog u-hu--helpuspam( RR>R RRR<R@Rt parse_argstfoo(RRBRtRCtargs((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_repl_parse_after_completes   *c C`s`t}|jd|jd|j}|jd|jd|jd}d}|jd|j}|jd}|jd |t|d t}d d d dddddgfddgfdddgfdddd d gfddgfdd d gff}x?|D]7\} } |jt|j ||| t| q!WdS(Nu--foou--barulistusetushowcS`sdS(N((((s0/Users/kislyuk/projects/argcomplete/test/test.pytabcsu--testudepthtfuncR=uu-hu--helpuliulist usushow ushow dudepth u show depth ( RR>RXRYt set_defaultsR RRRHR@R<( RRBtstshowRtsstdeRtRIRJRK((s0/Users/kislyuk/projects/argcomplete/test/test.pyttest_repl_subcommands*           cC`st}|jdddddg|jddddgt|d t}|jt|j||d td d dddg|jt|j||d td d ddg|jt|j||d td d dddgdS(NufooREuaaubbuccubarudueR=uu-hu--helpuaa (RR>R RRRHR@R<(RRBRt((s0/Users/kislyuk/projects/argcomplete/test/test.pyt&test_repl_reuse_parser_with_positionals N( R"R#R)R*R%R<RRRtunittesttexpectedFailureR(((s0/Users/kislyuk/projects/argcomplete/test/test.pyRhs   u__main__(,t __future__RRRRRR1RRottempfileRRRhRtabspathRitdirnamet__file__RRt argcompleteRR R targcomplete.completersR R targcomplete.compatR RRRRt version_infoRt unittest2R(tobjectRtTestCaseR&RR"tmain(((s0/Users/kislyuk/projects/argcomplete/test/test.pyts$"0:( 6\