Skip to content

Commit e6a3b5b

Browse files
committed
Add shell completions by shtab
See #1992 pytest --print-completion bash | sudo tee /usr/share/bash-completion/completions/pytest pytest --print-completion tcsh | sudo tee /etc/profile.d/pytest.completion.csh pytest --print-completion zsh | sudo tee /usr/share/zsh/site-functions/_pytest
1 parent 5bd41be commit e6a3b5b

File tree

10 files changed

+65
-3
lines changed

10 files changed

+65
-3
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ Wil Cooley
365365
William Lee
366366
Wim Glenn
367367
Wouter van Ackooy
368+
Wu Zhenyu
368369
Xixi Zhao
369370
Xuan Luong
370371
Xuecong Liao

changelog/10304.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added shell completions by shtab

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,16 @@ console_scripts =
6464
py.test=pytest:console_main
6565

6666
[options.extras_require]
67+
completion =
68+
shtab
6769
testing =
6870
argcomplete
6971
hypothesis>=3.56
7072
mock
7173
nose
7274
pygments>=2.7.2
7375
requests
76+
shtab
7477
xmlschema
7578

7679
[options.package_data]

src/_pytest/__init__.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__all__ = ["__version__", "version_tuple"]
1+
__all__ = ["__version__", "version_tuple", "shtab", "XML_FILE", "PREAMBLE"]
22

33
try:
44
from ._version import version as __version__, version_tuple
@@ -7,3 +7,24 @@
77
# unknown only works because we do poor mans version compare
88
__version__ = "unknown"
99
version_tuple = (0, 0, "unknown") # type:ignore[assignment]
10+
11+
try:
12+
import shtab
13+
except ImportError:
14+
from . import _shtab as shtab
15+
16+
# https://github.com/iterative/shtab/blob/5358dda86e8ea98bf801a43a24ad73cd9f820c63/examples/customcomplete.py#L11-L22
17+
XML_FILE = {
18+
"bash": "_shtab_greeter_compgen_xml_files",
19+
"zsh": "_files -g '*.xml'",
20+
"tcsh": "f:*.xml",
21+
}
22+
PREAMBLE = {
23+
"bash": """
24+
# $1=COMP_WORDS[1]
25+
_shtab_greeter_compgen_xml_files() {
26+
compgen -d -- $1 # recurse into subdirs
27+
compgen -f -X '!*?.xml' -- $1
28+
}
29+
"""
30+
}

src/_pytest/_shtab.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""A shim of shtab"""
2+
from argparse import Action
3+
from argparse import ArgumentParser
4+
from typing import Any
5+
from typing import Dict
6+
from typing import List
7+
8+
FILE = None
9+
DIRECTORY = DIR = None
10+
11+
12+
def add_argument_to(parser: ArgumentParser, *args: List[Any], **kwargs: Dict[str, Any]):
13+
Action.complete = None # type: ignore
14+
return parser

src/_pytest/config/argparsing.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from typing import Union
1818

1919
import _pytest._io
20+
from _pytest import PREAMBLE
21+
from _pytest import shtab
2022
from _pytest.compat import final
2123
from _pytest.config.exceptions import UsageError
2224
from _pytest.deprecated import ARGUMENT_PERCENT_DEFAULT
@@ -27,6 +29,7 @@
2729
if TYPE_CHECKING:
2830
from typing_extensions import Literal
2931

32+
3033
FILE_OR_DIR = "file_or_dir"
3134

3235

@@ -124,11 +127,19 @@ def _getparser(self) -> "MyOptionParser":
124127
if group.options:
125128
desc = group.description or group.name
126129
arggroup = optparser.add_argument_group(desc)
130+
if group.name == "debugconfig":
131+
shtab.add_argument_to(arggroup, preamble=PREAMBLE)
127132
for option in group.options:
128133
n = option.names()
129134
a = option.attrs()
130-
arggroup.add_argument(*n, **a)
135+
complete = a.get("complete")
136+
if complete:
137+
del a["complete"] # type: ignore
138+
action = arggroup.add_argument(*n, **a)
139+
if complete:
140+
action.complete = complete # type: ignore
131141
file_or_dir_arg = optparser.add_argument(FILE_OR_DIR, nargs="*")
142+
file_or_dir_arg.complete = shtab.FILE # type: ignore
132143
# bash like autocompletion for dirs (appending '/')
133144
# Type ignored because typeshed doesn't know about argcomplete.
134145
file_or_dir_arg.completer = filescompleter # type: ignore

src/_pytest/helpconfig.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Union
88

99
import pytest
10+
from _pytest import shtab
1011
from _pytest.config import Config
1112
from _pytest.config import ExitCode
1213
from _pytest.config import PrintHelp
@@ -86,6 +87,7 @@ def pytest_addoption(parser: Parser) -> None:
8687
help="Store internal tracing debug information in this log file. "
8788
"This file is opened with 'w' and truncated as a result, care advised. "
8889
"Default: pytestdebug.log.",
90+
complete=shtab.FILE,
8991
)
9092
group._addoption(
9193
"-o",

src/_pytest/junitxml.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from typing import Union
2222

2323
import pytest
24+
from . import XML_FILE
2425
from _pytest import nodes
2526
from _pytest import timing
2627
from _pytest._code.code import ExceptionRepr
@@ -33,7 +34,6 @@
3334
from _pytest.stash import StashKey
3435
from _pytest.terminal import TerminalReporter
3536

36-
3737
xml_key = StashKey["LogXML"]()
3838

3939

@@ -390,6 +390,7 @@ def pytest_addoption(parser: Parser) -> None:
390390
type=functools.partial(filename_arg, optname="--junitxml"),
391391
default=None,
392392
help="Create junit-xml style report file at given path",
393+
complete=XML_FILE,
393394
)
394395
group.addoption(
395396
"--junitprefix",

src/_pytest/logging.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from typing import Union
2020

2121
from _pytest import nodes
22+
from _pytest import shtab
2223
from _pytest._io import TerminalWriter
2324
from _pytest.capture import CaptureManager
2425
from _pytest.compat import final
@@ -35,6 +36,7 @@
3536
from _pytest.stash import StashKey
3637
from _pytest.terminal import TerminalReporter
3738

39+
3840
if TYPE_CHECKING:
3941
logging_StreamHandler = logging.StreamHandler[StringIO]
4042

@@ -272,6 +274,7 @@ def add_option_ini(option, dest, default=None, type=None, **kwargs):
272274
dest="log_file",
273275
default=None,
274276
help="Path to a file when logging will be written to",
277+
complete=shtab.FILE,
275278
)
276279
add_option_ini(
277280
"--log-file-level",

src/_pytest/main.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import _pytest._code
2525
from _pytest import nodes
26+
from _pytest import shtab
2627
from _pytest.compat import final
2728
from _pytest.compat import overload
2829
from _pytest.config import Config
@@ -128,6 +129,7 @@ def pytest_addoption(parser: Parser) -> None:
128129
dest="inifilename",
129130
help="Load configuration from `file` instead of trying to locate one of the "
130131
"implicit configuration files",
132+
complete=shtab.FILE,
131133
)
132134
group._addoption(
133135
"--continue-on-collection-errors",
@@ -143,6 +145,7 @@ def pytest_addoption(parser: Parser) -> None:
143145
help="Define root directory for tests. Can be relative path: 'root_dir', './root_dir', "
144146
"'root_dir/another_dir/'; absolute path: '/home/user/root_dir'; path with variables: "
145147
"'$HOME/root_dir'.",
148+
complete=shtab.DIR,
146149
)
147150

148151
group = parser.getgroup("collect", "collection")
@@ -183,6 +186,7 @@ def pytest_addoption(parser: Parser) -> None:
183186
metavar="dir",
184187
type=functools.partial(directory_arg, optname="--confcutdir"),
185188
help="Only load conftest.py's relative to specified dir",
189+
complete=shtab.DIR,
186190
)
187191
group.addoption(
188192
"--noconftest",
@@ -226,6 +230,7 @@ def pytest_addoption(parser: Parser) -> None:
226230
"Base temporary directory for this test run. "
227231
"(Warning: this directory is removed if it exists.)"
228232
),
233+
complete=shtab.DIR,
229234
)
230235

231236

0 commit comments

Comments
 (0)