Skip to content

Commit 796169c

Browse files
Show equivalent pytest command (#6363)
This is just a quick change to help users trouble-shoot problems with pytest. When there is a failure, we print out the command they can run at the shell to duplicate the error.
1 parent c02d504 commit 796169c

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

pythonFiles/testing_tools/adapter/pytest/_discovery.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@ def discover(pytestargs=None, hidestdio=False,
2828
# No tests were discovered.
2929
pass
3030
elif ec != 0:
31+
print(('equivalent command: {} -m pytest {}'
32+
).format(sys.executable, util.shlex_unsplit(pytestargs)))
3133
if hidestdio:
3234
print(stdio.getvalue(), file=sys.stderr)
3335
sys.stdout.flush()
3436
raise Exception('pytest discovery failed (exit code {})'.format(ec))
3537
if not _plugin._started:
38+
print(('equivalent command: {} -m pytest {}'
39+
).format(sys.executable, util.shlex_unsplit(pytestargs)))
3640
if hidestdio:
3741
print(stdio.getvalue(), file=sys.stderr)
3842
sys.stdout.flush()

pythonFiles/testing_tools/adapter/util.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,34 @@ def group_attr_names(attrnames):
5959
group = 'other'
6060
grouped[group].append(name)
6161
return grouped
62+
63+
64+
def shlex_unsplit(argv):
65+
"""Return the shell-safe string for the given arguments.
66+
67+
This effectively the equivalent of reversing shlex.split().
68+
"""
69+
argv = [_quote_arg(a) for a in argv]
70+
return ' '.join(argv)
71+
72+
73+
try:
74+
from shlex import quote as _quote_arg
75+
except ImportError:
76+
def _quote_arg(arg):
77+
parts = None
78+
for i, c in enumerate(arg):
79+
if c.isspace():
80+
pass
81+
elif c == '"':
82+
pass
83+
elif c == "'":
84+
c = "'\"'\"'"
85+
else:
86+
continue
87+
if parts is None:
88+
parts = list(arg)
89+
parts[i] = c
90+
if parts is not None:
91+
arg = "'" + ''.join(parts) + "'"
92+
return arg
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import shlex
5+
import unittest
6+
7+
from testing_tools.adapter.util import shlex_unsplit
8+
9+
10+
class ShlexUnsplitTests(unittest.TestCase):
11+
12+
def test_no_args(self):
13+
argv = []
14+
joined = shlex_unsplit(argv)
15+
16+
self.assertEqual(joined, '')
17+
self.assertEqual(shlex.split(joined), argv)
18+
19+
def test_one_arg(self):
20+
argv = ['spam']
21+
joined = shlex_unsplit(argv)
22+
23+
self.assertEqual(joined, 'spam')
24+
self.assertEqual(shlex.split(joined), argv)
25+
26+
def test_multiple_args(self):
27+
argv = [
28+
'-x', 'X',
29+
'-xyz',
30+
'spam',
31+
'eggs',
32+
]
33+
joined = shlex_unsplit(argv)
34+
35+
self.assertEqual(joined, '-x X -xyz spam eggs')
36+
self.assertEqual(shlex.split(joined), argv)
37+
38+
def test_whitespace(self):
39+
argv = [
40+
'-x', 'X Y Z',
41+
'spam spam\tspam',
42+
'eggs',
43+
]
44+
joined = shlex_unsplit(argv)
45+
46+
self.assertEqual(joined, "-x 'X Y Z' 'spam spam\tspam' eggs")
47+
self.assertEqual(shlex.split(joined), argv)
48+
49+
def test_quotation_marks(self):
50+
argv = [
51+
'-x', "'<quoted>'",
52+
'spam"spam"spam',
53+
"ham'ham'ham",
54+
'eggs',
55+
]
56+
joined = shlex_unsplit(argv)
57+
58+
self.assertEqual(joined, "-x ''\"'\"'<quoted>'\"'\"'' 'spam\"spam\"spam' 'ham'\"'\"'ham'\"'\"'ham' eggs")
59+
self.assertEqual(shlex.split(joined), argv)

0 commit comments

Comments
 (0)