bpo-43776: Remove list call from args in Popen repr (GH-25338)

Removes the `list` call in the Popen `repr`.

Current implementation:

For cmd = `python --version`,  with `shell=True`.

```bash
<Popen: returncode: None args: ['p', 'y', 't', 'h', 'o', 'n', ' ', '-', '-',...>
```

For `shell=False` and args=`['python', '--version']`, the output is correct:

```bash
<Popen: returncode: None args: ['python', '--version']>
```

With the new changes the `repr`  yields:

For cmd = `python --version`,  with `shell=True`:

```bash
<Popen: returncode: None args: 'python --version'>
```

For `shell=False` and args=`['python', '--version']`, the output:

```bash
<Popen: returncode: None args: ['python', '--version']>
```

Automerge-Triggered-By: GH:gpshead
This commit is contained in:
M. Kocher 2021-04-28 01:16:38 -07:00 committed by GitHub
parent f9bedb630e
commit db0c5b786d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 22 deletions

View File

@ -1003,7 +1003,7 @@ class Popen:
def __repr__(self): def __repr__(self):
obj_repr = ( obj_repr = (
f"<{self.__class__.__name__}: " f"<{self.__class__.__name__}: "
f"returncode: {self.returncode} args: {list(self.args)!r}>" f"returncode: {self.returncode} args: {self.args!r}>"
) )
if len(obj_repr) > 80: if len(obj_repr) > 80:
obj_repr = obj_repr[:76] + "...>" obj_repr = obj_repr[:76] + "...>"

View File

@ -23,6 +23,7 @@ import threading
import gc import gc
import textwrap import textwrap
import json import json
import pathlib
from test.support.os_helper import FakePath from test.support.os_helper import FakePath
try: try:
@ -1442,28 +1443,23 @@ class ProcessTestCase(BaseTestCase):
p.communicate(b"x" * 2**20) p.communicate(b"x" * 2**20)
def test_repr(self): def test_repr(self):
# Run a command that waits for user input, to check the repr() of path_cmd = pathlib.Path("my-tool.py")
# a Proc object while and after the sub-process runs. pathlib_cls = path_cmd.__class__.__name__
code = 'import sys; input(); sys.exit(57)'
cmd = [sys.executable, '-c', code]
result = "<Popen: returncode: {}"
with subprocess.Popen( cases = [
cmd, stdin=subprocess.PIPE, universal_newlines=True) as proc: ("ls", True, 123, "<Popen: returncode: 123 args: 'ls'>"),
self.assertIsNone(proc.returncode) ('a' * 100, True, 0,
self.assertTrue( "<Popen: returncode: 0 args: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...>"),
repr(proc).startswith(result.format(proc.returncode)) and (["ls"], False, None, "<Popen: returncode: None args: ['ls']>"),
repr(proc).endswith('>') (["ls", '--my-opts', 'a' * 100], False, None,
) "<Popen: returncode: None args: ['ls', '--my-opts', 'aaaaaaaaaaaaaaaaaaaaaaaa...>"),
(path_cmd, False, 7, f"<Popen: returncode: 7 args: {pathlib_cls}('my-tool.py')>")
proc.communicate(input='exit...\n') ]
proc.wait() with unittest.mock.patch.object(subprocess.Popen, '_execute_child'):
for cmd, shell, code, sx in cases:
self.assertIsNotNone(proc.returncode) p = subprocess.Popen(cmd, shell=shell)
self.assertTrue( p.returncode = code
repr(proc).startswith(result.format(proc.returncode)) and self.assertEqual(repr(p), sx)
repr(proc).endswith('>')
)
def test_communicate_epipe_only_stdin(self): def test_communicate_epipe_only_stdin(self):
# Issue 10963: communicate() should hide EPIPE # Issue 10963: communicate() should hide EPIPE

View File

@ -0,0 +1 @@
When :class:`subprocess.Popen` args are provided as a string or as :class:`pathlib.Path`, the Popen instance repr now shows the right thing.