argcomplete-0.8.1/0000755000076500000240000000000012355037462014647 5ustar kislyukstaff00000000000000argcomplete-0.8.1/argcomplete/0000755000076500000240000000000012355037462017151 5ustar kislyukstaff00000000000000argcomplete-0.8.1/argcomplete/__init__.py0000644000076500000240000004567112355036273021276 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 print_function, unicode_literals import os, sys, argparse, contextlib, subprocess, locale, re from . import my_shlex as shlex USING_PYTHON2 = True if sys.version_info < (3, 0) else False if not USING_PYTHON2: basestring = str sys_encoding = locale.getpreferredencoding() _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) from . import completers from .my_argparse import IntrospectiveArgumentParser, action_is_satisfied, action_is_open @contextlib.contextmanager def mute_stdout(): stdout = sys.stdout sys.stdout = open(os.devnull, 'w') yield sys.stdout = stdout @contextlib.contextmanager def mute_stderr(): stderr = sys.stderr sys.stderr = open(os.devnull, 'w') yield sys.stderr.close() sys.stderr = stderr class ArgcompleteException(Exception): pass def split_line(line, point): lexer = shlex.shlex(line, posix=True, punctuation_chars=True) words = [] def split_word(word): # TODO: make this less ugly point_in_word = len(word) + point - lexer.instream.tell() if isinstance(lexer.state, basestring) 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:] first_colon_pos = lexer.first_colon_pos if ':' in word else None return prequote, prefix, suffix, words, first_colon_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.") 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): pass def __call__(self, argument_parser, always_complete_options=True, exit_method=os._exit, output_stream=None, exclude=None, validator=None): ''' :param argument_parser: The argument parser to autocomplete on :type argument_parser: :class:`argparse.ArgumentParser` :param always_complete_options: Whether or not to autocomplete options even if an option string opening character (normally ``-``) has not been entered :type always_complete_options: boolean :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 .. 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. ''' 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) if validator is None: validator = default_validator self.validator = validator self.always_complete_options = always_complete_options self.exclude = exclude # print("", stream=debug_stream) # for v in 'COMP_CWORD', 'COMP_LINE', 'COMP_POINT', 'COMP_TYPE', 'COMP_KEY', '_ARGCOMPLETE_COMP_WORDBREAKS', 'COMP_WORDS': # 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)) if USING_PYTHON2: comp_line = comp_line.decode(sys_encoding) cword_prequote, cword_prefix, cword_suffix, comp_words, first_colon_pos = split_line(comp_line, comp_point) if os.environ['_ARGCOMPLETE'] == "2": # Hook recognized the first word as the interpreter comp_words.pop(0) debug(u"\nLINE: '{l}'\nPREQUOTE: '{pq}'\nPREFIX: '{p}'".format(l=comp_line, pq=cword_prequote, p=cword_prefix), u"\nSUFFIX: '{s}'".format(s=cword_suffix), u"\nWORDS:", comp_words) active_parsers = [argument_parser] parsed_args = argparse.Namespace() visited_actions = [] ''' 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. ''' def patchArgumentParser(parser): parser.__class__ = IntrospectiveArgumentParser for action in parser._actions: # 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) visited_actions.append(self) if self._orig_class == argparse._SubParsersAction: debug('orig class is a subparsers action: patching and running it') active_subparser = self._name_parser_map[values[0]] patchArgumentParser(active_subparser) active_parsers.append(active_subparser) self._orig_callable(parser, namespace, values, option_string=option_string) elif self._orig_class in safe_actions: self._orig_callable(parser, namespace, values, option_string=option_string) if getattr(action, "_orig_class", None): debug("Action", action, "already patched") action._orig_class = action.__class__ action._orig_callable = action.__call__ action.__class__ = IntrospectAction patchArgumentParser(argument_parser) try: debug("invoking parser with", comp_words[1:]) with mute_stderr(): a = argument_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") debug("Active parsers:", active_parsers) debug("Visited actions:", visited_actions) debug("Parse result namespace:", parsed_args) completions = self.collect_completions(active_parsers, parsed_args, cword_prefix, debug) completions = self.filter_completions(completions) completions = self.quote_completions(completions, cword_prequote, first_colon_pos) debug("\nReturning completions:", completions) output_stream.write(ifs.join(completions).encode(sys_encoding)) output_stream.flush() debug_stream.flush() exit_method(0) 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 = [] for parser in active_parsers: debug("Examining parser", parser) for action in parser._actions: debug("Examining action", action) if isinstance(action, argparse._SubParsersAction): subparser_activated = False for subparser in action._name_parser_map.values(): if subparser in active_parsers: subparser_activated = True if subparser_activated: # Parent parser completions are not valid in the subparser, so flush them completions = [] else: completions += [subcmd for subcmd in action.choices.keys() if subcmd.startswith(cword_prefix)] elif self.always_complete_options or (len(cword_prefix) > 0 and cword_prefix[0] in parser.prefix_chars): completions += [option for option in action.option_strings if option.startswith(cword_prefix)] debug("Active actions (L={l}): {a}".format(l=len(parser.active_actions), a=parser.active_actions)) # Only run completers if current word does not start with - (is not an optional) if len(cword_prefix) == 0 or cword_prefix[0] not in parser.prefix_chars: for active_action in parser.active_actions: if not active_action.option_strings: # action is a positional 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 and active_action.choices is not None: if not isinstance(active_action, argparse._SubParsersAction): completer = completers.ChoicesCompleter(active_action.choices) if completer: if len(active_action.option_strings) > 0: # only for optionals if not action_is_satisfied(active_action): # This means the current 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", active_action, "is unsatisfied") completions = [] if callable(completer): completions += [c for c in completer(prefix=cword_prefix, action=active_action, parsed_args=parsed_args) if self.validator(c, cword_prefix)] 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): completions.append(next_completion) debug("Completions:", completions) elif not isinstance(active_action, argparse._SubParsersAction): debug("Completer not available, falling back") try: # TODO: what happens if completions contain newlines? How do I make compgen use IFS? bashcomp_cmd = ['bash', '-c', "compgen -A file -- '{p}'".format(p=cword_prefix)] completions += subprocess.check_output(bashcomp_cmd).decode(sys_encoding).splitlines() except subprocess.CalledProcessError: pass return completions 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. if USING_PYTHON2: for i in range(len(completions)): if type(completions[i]) != unicode: completions[i] = completions[i].decode(sys_encoding) # 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, first_colon_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 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. ''' comp_wordbreaks = os.environ.get('_ARGCOMPLETE_COMP_WORDBREAKS', os.environ.get('COMP_WORDBREAKS', " \t\"'@><=;|&(:.")) if USING_PYTHON2: comp_wordbreaks = comp_wordbreaks.decode(sys_encoding) punctuation_chars = u'();<>|&!`' for char in punctuation_chars: if char not in comp_wordbreaks: comp_wordbreaks += char # If the word under the cursor was quoted, escape the quote char and add the leading quote back in. # Otherwise, escape all COMP_WORDBREAKS chars. if cword_prequote == '': # Bash mangles completions which contain colons. # This workaround has the same effect as __ltrim_colon_completions in bash_completion. if first_colon_pos: completions = [c[first_colon_pos+1:] for c in completions] for wordbreak_char in comp_wordbreaks: completions = [c.replace(wordbreak_char, '\\'+wordbreak_char) for c in completions] else: if cword_prequote == '"': for char in '`$!': completions = [c.replace(char, '\\'+char) for c in completions] completions = [cword_prequote+c.replace(cword_prequote, '\\'+cword_prequote) for c in completions] # Note: similar functionality in bash is turned off by supplying the "-o nospace" option to complete. # We can't use that functionality because bash is not smart enough to recognize continuation characters (/) for # which no space should be added. continuation_chars = '=/:' if len(completions) == 1 and completions[0][-1] not in continuation_chars: if cword_prequote == '' and not completions[0].endswith(' '): completions[0] += ' ' return completions 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-0.8.1/argcomplete/bash_completion.d/0000755000076500000240000000000012355037462022541 5ustar kislyukstaff00000000000000argcomplete-0.8.1/argcomplete/bash_completion.d/python-argcomplete.sh0000644000076500000240000000334512355036321026714 0ustar kislyukstaff00000000000000# Copyright 2012-2013, Andrey Kislyuk and argcomplete contributors. # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. _python_argcomplete_global() { local ARGCOMPLETE=0 if [[ "$1" == python* ]] || [[ "$1" == 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 set -- "${COMP_WORDS[1]}" fi elif which "$1" >/dev/null 2>&1; then local SCRIPT_NAME=$(which "$1") if (type -t pyenv && [[ "$SCRIPT_NAME" = $(pyenv root)/shims/* ]]) >/dev/null 2>&1; then local SCRIPT_NAME=$(pyenv which "$1") 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" \ _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \ _ARGCOMPLETE=$ARGCOMPLETE \ "$1" 8>&1 9>&2 1>/dev/null 2>&1) ) if [[ $? != 0 ]]; then unset COMPREPLY fi else type -t _completion_loader | grep -q 'function' && _completion_loader "$@" fi } complete -o nospace -o default -o bashdefault -D -F _python_argcomplete_global argcomplete-0.8.1/argcomplete/completers.py0000644000076500000240000000525712235544430021704 0ustar kislyukstaff00000000000000# Copyright 2012-2013, Andrey Kislyuk and argcomplete contributors. # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. import os import sys import subprocess def _wrapcall(*args, **kargs): try: return subprocess.check_output(*args,**kargs).decode().splitlines() except AttributeError: return _wrapcall_2_6(*args, **kargs) except subprocess.CalledProcessError: return [] def _wrapcall_2_6(*args, **kargs): try: # no check_output in 2.6, if 'stdout' in kargs: raise ValueError('stdout argument not allowed, it will be overridden.') process = subprocess.Popen( stdout=subprocess.PIPE, *args, **kargs) output, unused_err = process.communicate() retcode = process.poll() if retcode: cmd = kargs.get("args") if cmd is None: cmd = args[0] raise subprocess.CalledProcessError(retcode, cmd) return output.decode().splitlines() except subprocess.CalledProcessError: return [] class ChoicesCompleter(object): def __init__(self, choices=[]): self.choices = choices 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 type(allowednames) is str: 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 = _wrapcall(['bash','-c', "compgen -A directory -- '{p}'".format(p=prefix)]) completion += [ f + '/' for f in files] for x in self.allowednames: completion += _wrapcall(['bash', '-c', "compgen -A file -X '!*.{0}' -- '{p}'".format(x,p=prefix)]) else: completion += _wrapcall(['bash', '-c', "compgen -A file -- '{p}'".format(p=prefix)]) anticomp = _wrapcall(['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 argcomplete-0.8.1/argcomplete/my_argparse.py0000644000076500000240000003166012235544430022035 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 from argparse import OPTIONAL, ZERO_OR_MORE, ONE_OR_MORE, REMAINDER, PARSER from argparse import _get_action_name, _ 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 = getattr(action, 'num_consumed_args', 0) if action.nargs == ONE_OR_MORE and num_consumed_args < 1: return False else: if action.nargs is None: action.nargs = 1 try: return num_consumed_args == action.nargs except: return True def action_is_open(action): ''' Returns True if action could consume more arguments (i.e., its pattern is open). ''' return action.nargs in [ZERO_OR_MORE, ONE_OR_MORE, PARSER, REMAINDER] 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): 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 = {} 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() 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: action(self, namespace, argument_values, option_string) # 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 action.num_consumed_args = 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) if not action_is_open(action): self.active_actions.remove(action) elif action.nargs == OPTIONAL and len(args) == 1: self.active_actions.remove(action) action.num_consumed_args = len(args) # 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): if arg_count > 0: # Added by argcomplete self.active_actions = [action] # Added by argcomplete else: # Added by argcomplete self.active_actions.append(action) # Added by argcomplete args = arg_strings[start_index: start_index + arg_count] start_index += arg_count action.num_consumed_args = len(args) 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-0.8.1/argcomplete/my_shlex.py0000644000076500000240000002643112235544430021354 0ustar kislyukstaff00000000000000# -*- coding: utf-8 -*- # This copy of shlex.py is distributed with argcomplete. # It incorporates changes proposed in http://bugs.python.org/issue1521950 and changes to allow it to match Unicode # word characters. """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, January 2012. import os.path, sys, re from collections import deque # Note: cStringIO is not compatible with Unicode try: from StringIO import StringIO except ImportError: from io import StringIO try: basestring except NameError: basestring = str __all__ = ["shlex", "split"] class UnicodeWordchars: ''' A replacement for shlex.wordchars that also matches (__contains__) any Unicode wordchars. ''' def __init__(self, wordchars): self.wordchars = wordchars self.uw_regex = re.compile('\w', flags=re.UNICODE) def __contains__(self, c): return c in self.wordchars or self.uw_regex.match(c) class shlex: "A lexical analyzer class for simple shell-like syntaxes." def __init__(self, instream=None, infile=None, posix=False, punctuation_chars=False): 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_') 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 self.wordchars = ''.join(c for c in self.wordchars if c not in self.punctuation_chars) for c in punctuation_chars: if c in self.wordchars: self.wordchars.remove(c) if self.posix: self.wordchars = UnicodeWordchars(self.wordchars) self.first_colon_pos = None def push_token(self, tok): "Push a token onto the stack popped by the get_token method" self.pushback.appendleft(tok) def push_source(self, newstream, newfile=None): "Push an input source onto the lexer's input source stack." 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 def pop_source(self): "Pop the input source stack." self.instream.close() (self.infile, self.instream, self.lineno) = self.filestack.popleft() 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() 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 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.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.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 # 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 # 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: 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 if nextchar == ':': self.first_colon_pos = len(self.token)-1 else: if self.punctuation_chars: self._pushback_chars.append(nextchar) else: self.pushback.appendleft(nextchar) self.state = ' ' if self.token: break # emit current token else: continue result = self.token self.token = '' if self.posix and not quoted and result == '': result = 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. 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 def split(s, comments=False, posix=True, punctuation_chars=False): lex = shlex(s, posix=posix, punctuation_chars=punctuation_chars) lex.whitespace_split = True if not comments: lex.commenters = '' return list(lex) argcomplete-0.8.1/argcomplete.egg-info/0000755000076500000240000000000012355037462020643 5ustar kislyukstaff00000000000000argcomplete-0.8.1/argcomplete.egg-info/dependency_links.txt0000644000076500000240000000000112355037462024711 0ustar kislyukstaff00000000000000 argcomplete-0.8.1/argcomplete.egg-info/not-zip-safe0000644000076500000240000000000112315603724023065 0ustar kislyukstaff00000000000000 argcomplete-0.8.1/argcomplete.egg-info/PKG-INFO0000644000076500000240000003441512355037462021747 0ustar kislyukstaff00000000000000Metadata-Version: 1.1 Name: argcomplete Version: 0.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 or zsh as your shell * 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)" 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. 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 = 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')) 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() 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 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) `_ 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://pypip.in/v/argcomplete/badge.png :target: https://warehouse.python.org/project/argcomplete/ .. image:: https://pypip.in/d/argcomplete/badge.png :target: https://warehouse.python.org/project/argcomplete/ 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: Development Status :: 5 - Production/Stable Classifier: Topic :: Software Development :: Libraries :: Python Modules argcomplete-0.8.1/argcomplete.egg-info/SOURCES.txt0000644000076500000240000000104512355037462022527 0ustar kislyukstaff00000000000000Authors.rst Changes.rst LICENSE.rst MANIFEST.in README.rst setup.cfg setup.py argcomplete/__init__.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/top_level.txt argcomplete/bash_completion.d/python-argcomplete.sh scripts/activate-global-python-argcomplete scripts/python-argcomplete-check-easy-install-script scripts/register-python-argcomplete test/test.pyargcomplete-0.8.1/argcomplete.egg-info/top_level.txt0000644000076500000240000000001412355037462023370 0ustar kislyukstaff00000000000000argcomplete argcomplete-0.8.1/Authors.rst0000644000076500000240000000004312277743572017034 0ustar kislyukstaff00000000000000Andrey Kislyuk argcomplete-0.8.1/Changes.rst0000644000076500000240000000234312355037401016744 0ustar kislyukstaff00000000000000Version 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-0.8.1/LICENSE.rst0000644000076500000240000002367612235544430016474 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-0.8.1/MANIFEST.in0000644000076500000240000000006612235544430016402 0ustar kislyukstaff00000000000000include argcomplete/bash_completion.d/* include *.rst argcomplete-0.8.1/PKG-INFO0000644000076500000240000003441512355037462015753 0ustar kislyukstaff00000000000000Metadata-Version: 1.1 Name: argcomplete Version: 0.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 or zsh as your shell * 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)" 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. 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 = 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')) 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() 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 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) `_ 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://pypip.in/v/argcomplete/badge.png :target: https://warehouse.python.org/project/argcomplete/ .. image:: https://pypip.in/d/argcomplete/badge.png :target: https://warehouse.python.org/project/argcomplete/ 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: Development Status :: 5 - Production/Stable Classifier: Topic :: Software Development :: Libraries :: Python Modules argcomplete-0.8.1/README.rst0000644000076500000240000002663312355035723016346 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 or zsh as your shell * 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)" 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. 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 = 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')) 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() 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 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) `_ 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://pypip.in/v/argcomplete/badge.png :target: https://warehouse.python.org/project/argcomplete/ .. image:: https://pypip.in/d/argcomplete/badge.png :target: https://warehouse.python.org/project/argcomplete/ argcomplete-0.8.1/scripts/0000755000076500000240000000000012355037462016336 5ustar kislyukstaff00000000000000argcomplete-0.8.1/scripts/activate-global-python-argcomplete0000755000076500000240000000344312253426565025150 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 parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) dest_opt = parser.add_argument("--dest", help="Specify the bash completion modules directory to install into", default="/etc/bash_completion.d") parser.add_argument("--user", help="Install into user directory (~/.bash_completion.d/)", action='store_true') 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 != '-': 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.dest == '-': sys.stdout.write(open(activator).read()) else: dest = os.path.join(args.dest, "python-argcomplete.sh") sys.stdout.write("Installing bash completion script " + dest + "\n") try: shutil.copy(activator, dest) 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-0.8.1/scripts/python-argcomplete-check-easy-install-script0000755000076500000240000000477412277743606027110 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-0.8.1/scripts/register-python-argcomplete0000755000076500000240000000241412355036341023723 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)" ''' import os, sys, argparse shellcode = ''' _python_argcomplete() { local IFS='\013' COMPREPLY=( $(IFS="$IFS" \ COMP_LINE="$COMP_LINE" \ COMP_POINT="$COMP_POINT" \ _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \ _ARGCOMPLETE=1 \ "$1" 8>&1 9>&2 1>/dev/null 2>/dev/null) ) if [[ $? != 0 ]]; then unset COMPREPLY fi } complete -o nospace -o default -F _python_argcomplete "%s" ''' parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("executable") if len(sys.argv)==1: parser.print_help() sys.exit(1) args = parser.parse_args() sys.stdout.write(shellcode % args.executable) argcomplete-0.8.1/setup.cfg0000644000076500000240000000022712355037462016471 0ustar kislyukstaff00000000000000[bdist_rpm] provides = python-argcomplete doc_files = AUTHORS.rst README.rst LICENSE.rst [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 argcomplete-0.8.1/setup.py0000755000076500000240000000251112355037441016360 0ustar kislyukstaff00000000000000#!/usr/bin/env python import glob from setuptools import setup, find_packages install_requires = [] try: import argparse except ImportError: install_requires.append('argparse') setup( name='argcomplete', version='0.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, 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'], 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', 'Development Status :: 5 - Production/Stable', 'Topic :: Software Development :: Libraries :: Python Modules' ] ) argcomplete-0.8.1/test/0000755000076500000240000000000012355037462015626 5ustar kislyukstaff00000000000000argcomplete-0.8.1/test/test.py0000755000076500000240000002573112355036613017167 0ustar kislyukstaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import os, sys, shutil python2 = True if sys.version_info < (3, 0) else False if python2: # Try to reset default encoding to a sane value # Note: This is incompatible with pypy import platform if platform.python_implementation() != "PyPy": try: import locale reload(sys).setdefaultencoding(locale.getdefaultlocale()[1]) except: pass if sys.version_info >= (2, 7): import unittest else: import unittest2 as unittest from tempfile import TemporaryFile, mkdtemp sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) from argparse import ArgumentParser from argcomplete import * IFS = '\013' 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): os.environ['_ARGCOMPLETE'] = "yes" os.environ['_ARC_DEBUG'] = "yes" os.environ['IFS'] = IFS def tearDown(self): pass def run_completer(self, parser, command, point=None, **kwargs): if python2: command = unicode(command) if point is None: if python2: point = str(len(command)) else: # Adjust point for wide chars point = str(len(command.encode(locale.getpreferredencoding()))) with TemporaryFile() as t: #os.environ['COMP_LINE'] = command.encode(locale.getpreferredencoding()) os.environ['COMP_LINE'] = command os.environ['COMP_POINT'] = point os.environ['_ARGCOMPLETE_COMP_WORDBREAKS'] = '"\'@><=;|&(:' self.assertRaises(SystemExit, autocomplete, parser, output_stream=t, exit_method=sys.exit, **kwargs) t.seek(0) return t.read().decode(locale.getpreferredencoding()).split(IFS) def test_basic_completion(self): p = ArgumentParser() p.add_argument("--foo") p.add_argument("--bar") completions = self.run_completer(p, "prog ") assert(set(completions) == set(['-h', '--help', '--foo', '--bar'])) def test_choices(self): def make_parser(): parser = argparse.ArgumentParser() parser.add_argument('--ship', choices=['submarine', '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_action_activation(self): def make_parser(): parser = argparse.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 = argparse.ArgumentParser() 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 ", ['build', '-h', '--help']), ("prog bu", ['build ']), ("prog build ", ['bus', 'car', '--profile', '-h', '--help']), ("prog build ca", ['car ']), ("prog build car ", ['--profile', '-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 = argparse.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_file_completion(self): # setup and teardown should probably be in class from argcomplete.completers import FilesCompleter with TempDir(prefix='test_dir_fc', dir='.') as t: 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_subparsers(self): def make_parser(): parser = argparse.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 ", ['on a train', 'with a goat', 'on a boat', 'in the rain', '--help', '-h']), ("prog eggs ", ['on a train', 'with a goat', 'on a boat', 'in the rain', '--help', '-h']), ("prog eggs \"on a", ['\"on a train', '\"on a boat']), ("prog eggs on\\ a", ['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'])) @unittest.skipIf(python2 and sys.getdefaultencoding() != locale.getdefaultlocale()[1], "Skip for python 2 due to its text encoding deficiencies") def test_non_ascii(self): def make_parser(): parser = argparse.ArgumentParser() parser.add_argument(u'--книга', choices=[u'Трудно быть богом', u'Парень из преисподней', u'Понедельник начинается в субботу']) return parser expected_outputs = (("prog ", [u'--книга', '-h', '--help']), (u"prog --книга ", [u'Трудно быть богом', u'Парень из преисподней', u'Понедельник начинается в субботу']), (u"prog --книга П", [u'Парень из преисподней', u'Понедельник начинается в субботу']), (u"prog --книга Пу", ['']), ) for cmd, output in expected_outputs: if python2: output = [o.decode(locale.getpreferredencoding()) for o in output] self.assertEqual(set(self.run_completer(make_parser(), cmd)), set(output)) def test_custom_validator(self): def make_parser(): parser = argparse.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 = argparse.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)) if __name__ == '__main__': unittest.main()