Coverage for /opt/homebrew/lib/python3.11/site-packages/_pytest/_argcomplete.py: 38%

37 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-05-04 13:14 +0700

1"""Allow bash-completion for argparse with argcomplete if installed. 

2 

3Needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail 

4to find the magic string, so _ARGCOMPLETE env. var is never set, and 

5this does not need special code). 

6 

7Function try_argcomplete(parser) should be called directly before 

8the call to ArgumentParser.parse_args(). 

9 

10The filescompleter is what you normally would use on the positional 

11arguments specification, in order to get "dirname/" after "dirn<TAB>" 

12instead of the default "dirname ": 

13 

14 optparser.add_argument(Config._file_or_dir, nargs='*').completer=filescompleter 

15 

16Other, application specific, completers should go in the file 

17doing the add_argument calls as they need to be specified as .completer 

18attributes as well. (If argcomplete is not installed, the function the 

19attribute points to will not be used). 

20 

21SPEEDUP 

22======= 

23 

24The generic argcomplete script for bash-completion 

25(/etc/bash_completion.d/python-argcomplete.sh) 

26uses a python program to determine startup script generated by pip. 

27You can speed up completion somewhat by changing this script to include 

28 # PYTHON_ARGCOMPLETE_OK 

29so the python-argcomplete-check-easy-install-script does not 

30need to be called to find the entry point of the code and see if that is 

31marked with PYTHON_ARGCOMPLETE_OK. 

32 

33INSTALL/DEBUGGING 

34================= 

35 

36To include this support in another application that has setup.py generated 

37scripts: 

38 

39- Add the line: 

40 # PYTHON_ARGCOMPLETE_OK 

41 near the top of the main python entry point. 

42 

43- Include in the file calling parse_args(): 

44 from _argcomplete import try_argcomplete, filescompleter 

45 Call try_argcomplete just before parse_args(), and optionally add 

46 filescompleter to the positional arguments' add_argument(). 

47 

48If things do not work right away: 

49 

50- Switch on argcomplete debugging with (also helpful when doing custom 

51 completers): 

52 export _ARC_DEBUG=1 

53 

54- Run: 

55 python-argcomplete-check-easy-install-script $(which appname) 

56 echo $? 

57 will echo 0 if the magic line has been found, 1 if not. 

58 

59- Sometimes it helps to find early on errors using: 

60 _ARGCOMPLETE=1 _ARC_DEBUG=1 appname 

61 which should throw a KeyError: 'COMPLINE' (which is properly set by the 

62 global argcomplete script). 

63""" 

64import argparse 

65import os 

66import sys 

67from glob import glob 

68from typing import Any 

69from typing import List 

70from typing import Optional 

71 

72 

73class FastFilesCompleter: 

74 """Fast file completer class.""" 

75 

76 def __init__(self, directories: bool = True) -> None: 

77 self.directories = directories 

78 

79 def __call__(self, prefix: str, **kwargs: Any) -> List[str]: 

80 # Only called on non option completions. 

81 if os.path.sep in prefix[1:]: 

82 prefix_dir = len(os.path.dirname(prefix) + os.path.sep) 

83 else: 

84 prefix_dir = 0 

85 completion = [] 

86 globbed = [] 

87 if "*" not in prefix and "?" not in prefix: 

88 # We are on unix, otherwise no bash. 

89 if not prefix or prefix[-1] == os.path.sep: 

90 globbed.extend(glob(prefix + ".*")) 

91 prefix += "*" 

92 globbed.extend(glob(prefix)) 

93 for x in sorted(globbed): 

94 if os.path.isdir(x): 

95 x += "/" 

96 # Append stripping the prefix (like bash, not like compgen). 

97 completion.append(x[prefix_dir:]) 

98 return completion 

99 

100 

101if os.environ.get("_ARGCOMPLETE"): 

102 try: 

103 import argcomplete.completers 

104 except ImportError: 

105 sys.exit(-1) 

106 filescompleter: Optional[FastFilesCompleter] = FastFilesCompleter() 

107 

108 def try_argcomplete(parser: argparse.ArgumentParser) -> None: 

109 argcomplete.autocomplete(parser, always_complete_options=False) 

110 

111else: 

112 

113 def try_argcomplete(parser: argparse.ArgumentParser) -> None: 

114 pass 

115 

116 filescompleter = None