Skip to content

Commit

Permalink
configurable exit method, add side effects warning
Browse files Browse the repository at this point in the history
  • Loading branch information
kislyuk committed Nov 28, 2012
1 parent 21005c6 commit 9e30c11
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 8 deletions.
8 changes: 8 additions & 0 deletions README.rst
Expand Up @@ -46,6 +46,14 @@ This method is the entry point to the module. It must be called **after** Argume
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
:meth:`argcomplete.autocomplete()` is called. After sending completions, it exits using ``exit_method``. 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 ``<TAB>`` (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 :meth:`argcomplete.autocomplete()` as early as
possible in your execution flow.

Specifying completers
---------------------
Expand Down
12 changes: 5 additions & 7 deletions argcomplete/__init__.py
Expand Up @@ -63,12 +63,14 @@ def split_word(word):
else:
raise ArgcompleteException("unexpected state? TODO")

def autocomplete(argument_parser, always_complete_options=True, output_stream=None):
def autocomplete(argument_parser, always_complete_options=True, exit_method=os._exit, output_stream=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: method
'''

if '_ARGCOMPLETE' not in os.environ:
Expand All @@ -80,7 +82,7 @@ def autocomplete(argument_parser, always_complete_options=True, output_stream=No
output_stream = os.fdopen(8, 'wb')
except:
print >>debug_stream, "Unable to open fd 8 for writing, quitting"
os._exit(1)
exit_method(1)

# print >> debug_stream, ""
# for v in 'COMP_CWORD', 'COMP_LINE', 'COMP_POINT', 'COMP_TYPE', 'COMP_KEY', 'COMP_WORDBREAKS', 'COMP_WORDS':
Expand Down Expand Up @@ -201,11 +203,7 @@ def __call__(self, parser, namespace, values, option_string=None):
debug_stream.flush()
# os.fsync(debug_stream.fileno())

if '_ARC_DEBUG' in os.environ:
exit()
else:
# Avoid firing any atexits
os._exit(0)
exit_method(0)

# COMP_CWORD
# COMP_LINE
Expand Down
2 changes: 1 addition & 1 deletion test/test.py
Expand Up @@ -27,7 +27,7 @@ def run_completer(self, parser, command, point=None):
os.environ['COMP_LINE'] = command
os.environ['COMP_POINT'] = point if point else str(len(command))
with self.assertRaises(SystemExit):
autocomplete(parser, output_stream=t)
autocomplete(parser, output_stream=t, exit_method=sys.exit)
t.seek(0)
return t.read().split(IFS)

Expand Down

0 comments on commit 9e30c11

Please sign in to comment.