aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/pytest/py3/_pytest/_argcomplete.py
blob: 508f65d5d00d2f20f9172db9f0f3e43b3ba7f627 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
"""Allow bash-completion for argparse with argcomplete if installed.

Needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
to find the magic string, so _ARGCOMPLETE env. var is never set, and 
this does not need special code).
 
Function try_argcomplete(parser) should be called directly before 
the call to ArgumentParser.parse_args(). 
 
The filescompleter is what you normally would use on the positional 
arguments specification, in order to get "dirname/" after "dirn<TAB>" 
instead of the default "dirname ": 
 
   optparser.add_argument(Config._file_or_dir, nargs='*').completer=filescompleter
 
Other, application specific, completers should go in the file 
doing the add_argument calls as they need to be specified as .completer 
attributes as well. (If argcomplete is not installed, the function the 
attribute points to will not be used). 
 
SPEEDUP 
======= 

The generic argcomplete script for bash-completion 
(/etc/bash_completion.d/python-argcomplete.sh)
uses a python program to determine startup script generated by pip. 
You can speed up completion somewhat by changing this script to include 
  # PYTHON_ARGCOMPLETE_OK 
so the python-argcomplete-check-easy-install-script does not
need to be called to find the entry point of the code and see if that is 
marked  with PYTHON_ARGCOMPLETE_OK.
 
INSTALL/DEBUGGING 
================= 

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

- Add the line:
    # PYTHON_ARGCOMPLETE_OK 
  near the top of the main python entry point.

- Include in the file calling parse_args():
    from _argcomplete import try_argcomplete, filescompleter 
  Call try_argcomplete just before parse_args(), and optionally add
  filescompleter to the positional arguments' add_argument().

If things do not work right away: 

- Switch on argcomplete debugging with (also helpful when doing custom
  completers): 
    export _ARC_DEBUG=1 

- Run:
    python-argcomplete-check-easy-install-script $(which appname) 
    echo $? 
  will echo 0 if the magic line has been found, 1 if not.

- Sometimes it helps to find early on errors using:
    _ARGCOMPLETE=1 _ARC_DEBUG=1 appname 
  which should throw a KeyError: 'COMPLINE' (which is properly set by the 
  global argcomplete script). 
""" 
import argparse
import os 
import sys 
from glob import glob 
from typing import Any
from typing import List
from typing import Optional
 
 
class FastFilesCompleter:
    """Fast file completer class."""
 
    def __init__(self, directories: bool = True) -> None:
        self.directories = directories 
 
    def __call__(self, prefix: str, **kwargs: Any) -> List[str]:
        # Only called on non option completions.
        if os.path.sep in prefix[1:]: 
            prefix_dir = len(os.path.dirname(prefix) + os.path.sep) 
        else: 
            prefix_dir = 0 
        completion = [] 
        globbed = [] 
        if "*" not in prefix and "?" not in prefix: 
            # We are on unix, otherwise no bash.
            if not prefix or prefix[-1] == os.path.sep: 
                globbed.extend(glob(prefix + ".*")) 
            prefix += "*" 
        globbed.extend(glob(prefix)) 
        for x in sorted(globbed): 
            if os.path.isdir(x): 
                x += "/" 
            # Append stripping the prefix (like bash, not like compgen).
            completion.append(x[prefix_dir:]) 
        return completion 
 
 
if os.environ.get("_ARGCOMPLETE"): 
    try: 
        import argcomplete.completers 
    except ImportError: 
        sys.exit(-1) 
    filescompleter: Optional[FastFilesCompleter] = FastFilesCompleter()
 
    def try_argcomplete(parser: argparse.ArgumentParser) -> None:
        argcomplete.autocomplete(parser, always_complete_options=False) 
 
 
else: 
 
    def try_argcomplete(parser: argparse.ArgumentParser) -> None:
        pass 
 
    filescompleter = None