Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/argcomplete/completers.py: 38%
68 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:31 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:31 +0000
1# Copyright 2012-2023, Andrey Kislyuk and argcomplete contributors.
2# Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info.
4import argparse
5import os
6import subprocess
9def _call(*args, **kwargs):
10 # TODO: replace "universal_newlines" with "text" once 3.6 support is dropped
11 kwargs["universal_newlines"] = True
12 try:
13 return subprocess.check_output(*args, **kwargs).splitlines()
14 except subprocess.CalledProcessError:
15 return []
18class BaseCompleter:
19 """
20 This is the base class that all argcomplete completers should subclass.
21 """
23 def __call__(
24 self, *, prefix: str, action: argparse.Action, parser: argparse.ArgumentParser, parsed_args: argparse.Namespace
25 ):
26 raise NotImplementedError("This method should be implemented by a subclass.")
29class ChoicesCompleter(BaseCompleter):
30 def __init__(self, choices):
31 self.choices = choices
33 def _convert(self, choice):
34 if not isinstance(choice, str):
35 choice = str(choice)
36 return choice
38 def __call__(self, **kwargs):
39 return (self._convert(c) for c in self.choices)
42EnvironCompleter = ChoicesCompleter(os.environ)
45class FilesCompleter(BaseCompleter):
46 """
47 File completer class, optionally takes a list of allowed extensions
48 """
50 def __init__(self, allowednames=(), directories=True):
51 # Fix if someone passes in a string instead of a list
52 if isinstance(allowednames, (str, bytes)):
53 allowednames = [allowednames]
55 self.allowednames = [x.lstrip("*").lstrip(".") for x in allowednames]
56 self.directories = directories
58 def __call__(self, prefix, **kwargs):
59 completion = []
60 if self.allowednames:
61 if self.directories:
62 files = _call(["bash", "-c", "compgen -A directory -- '{p}'".format(p=prefix)])
63 completion += [f + "/" for f in files]
64 for x in self.allowednames:
65 completion += _call(["bash", "-c", "compgen -A file -X '!*.{0}' -- '{p}'".format(x, p=prefix)])
66 else:
67 completion += _call(["bash", "-c", "compgen -A file -- '{p}'".format(p=prefix)])
68 anticomp = _call(["bash", "-c", "compgen -A directory -- '{p}'".format(p=prefix)])
69 completion = list(set(completion) - set(anticomp))
71 if self.directories:
72 completion += [f + "/" for f in anticomp]
73 return completion
76class _FilteredFilesCompleter(BaseCompleter):
77 def __init__(self, predicate):
78 """
79 Create the completer
81 A predicate accepts as its only argument a candidate path and either
82 accepts it or rejects it.
83 """
84 assert predicate, "Expected a callable predicate"
85 self.predicate = predicate
87 def __call__(self, prefix, **kwargs):
88 """
89 Provide completions on prefix
90 """
91 target_dir = os.path.dirname(prefix)
92 try:
93 names = os.listdir(target_dir or ".")
94 except Exception:
95 return # empty iterator
96 incomplete_part = os.path.basename(prefix)
97 # Iterate on target_dir entries and filter on given predicate
98 for name in names:
99 if not name.startswith(incomplete_part):
100 continue
101 candidate = os.path.join(target_dir, name)
102 if not self.predicate(candidate):
103 continue
104 yield candidate + "/" if os.path.isdir(candidate) else candidate
107class DirectoriesCompleter(_FilteredFilesCompleter):
108 def __init__(self):
109 _FilteredFilesCompleter.__init__(self, predicate=os.path.isdir)
112class SuppressCompleter(BaseCompleter):
113 """
114 A completer used to suppress the completion of specific arguments
115 """
117 def __init__(self):
118 pass
120 def suppress(self):
121 """
122 Decide if the completion should be suppressed
123 """
124 return True