_argcomplete.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. # -*- coding: utf-8 -*-
  2. """allow bash-completion for argparse with argcomplete if installed
  3. needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
  4. to find the magic string, so _ARGCOMPLETE env. var is never set, and
  5. this does not need special code.
  6. Function try_argcomplete(parser) should be called directly before
  7. the call to ArgumentParser.parse_args().
  8. The filescompleter is what you normally would use on the positional
  9. arguments specification, in order to get "dirname/" after "dirn<TAB>"
  10. instead of the default "dirname ":
  11. optparser.add_argument(Config._file_or_dir, nargs='*'
  12. ).completer=filescompleter
  13. Other, application specific, completers should go in the file
  14. doing the add_argument calls as they need to be specified as .completer
  15. attributes as well. (If argcomplete is not installed, the function the
  16. attribute points to will not be used).
  17. SPEEDUP
  18. =======
  19. The generic argcomplete script for bash-completion
  20. (/etc/bash_completion.d/python-argcomplete.sh )
  21. uses a python program to determine startup script generated by pip.
  22. You can speed up completion somewhat by changing this script to include
  23. # PYTHON_ARGCOMPLETE_OK
  24. so the the python-argcomplete-check-easy-install-script does not
  25. need to be called to find the entry point of the code and see if that is
  26. marked with PYTHON_ARGCOMPLETE_OK
  27. INSTALL/DEBUGGING
  28. =================
  29. To include this support in another application that has setup.py generated
  30. scripts:
  31. - add the line:
  32. # PYTHON_ARGCOMPLETE_OK
  33. near the top of the main python entry point
  34. - include in the file calling parse_args():
  35. from _argcomplete import try_argcomplete, filescompleter
  36. , call try_argcomplete just before parse_args(), and optionally add
  37. filescompleter to the positional arguments' add_argument()
  38. If things do not work right away:
  39. - switch on argcomplete debugging with (also helpful when doing custom
  40. completers):
  41. export _ARC_DEBUG=1
  42. - run:
  43. python-argcomplete-check-easy-install-script $(which appname)
  44. echo $?
  45. will echo 0 if the magic line has been found, 1 if not
  46. - sometimes it helps to find early on errors using:
  47. _ARGCOMPLETE=1 _ARC_DEBUG=1 appname
  48. which should throw a KeyError: 'COMPLINE' (which is properly set by the
  49. global argcomplete script).
  50. """
  51. from __future__ import absolute_import
  52. from __future__ import division
  53. from __future__ import print_function
  54. import os
  55. import sys
  56. from glob import glob
  57. class FastFilesCompleter(object):
  58. "Fast file completer class"
  59. def __init__(self, directories=True):
  60. self.directories = directories
  61. def __call__(self, prefix, **kwargs):
  62. """only called on non option completions"""
  63. if os.path.sep in prefix[1:]:
  64. prefix_dir = len(os.path.dirname(prefix) + os.path.sep)
  65. else:
  66. prefix_dir = 0
  67. completion = []
  68. globbed = []
  69. if "*" not in prefix and "?" not in prefix:
  70. # we are on unix, otherwise no bash
  71. if not prefix or prefix[-1] == os.path.sep:
  72. globbed.extend(glob(prefix + ".*"))
  73. prefix += "*"
  74. globbed.extend(glob(prefix))
  75. for x in sorted(globbed):
  76. if os.path.isdir(x):
  77. x += "/"
  78. # append stripping the prefix (like bash, not like compgen)
  79. completion.append(x[prefix_dir:])
  80. return completion
  81. if os.environ.get("_ARGCOMPLETE"):
  82. try:
  83. import argcomplete.completers
  84. except ImportError:
  85. sys.exit(-1)
  86. filescompleter = FastFilesCompleter()
  87. def try_argcomplete(parser):
  88. argcomplete.autocomplete(parser, always_complete_options=False)
  89. else:
  90. def try_argcomplete(parser):
  91. pass
  92. filescompleter = None