summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2020-05-02 15:32:17 +0200
committerGiampaolo Rodola <g.rodola@gmail.com>2020-05-02 15:32:17 +0200
commitd090aac2ce9aa46ee469d4c0c14fc21061b78d72 (patch)
tree17a33f4656be58c9ae98106d25eeb176d6bbdfc9
parentd7afd749a84510da139679be684ff4f6f79fa330 (diff)
downloadpsutil-wait-exit-code.tar.gz
Enhance Process repr and add exit codewait-exit-code
Show exit code if wait() was used and also use cached name if name() fails.
-rw-r--r--HISTORY.rst5
-rw-r--r--psutil/__init__.py8
-rw-r--r--psutil/tests/__init__.py7
-rwxr-xr-xpsutil/tests/test_misc.py20
4 files changed, 27 insertions, 13 deletions
diff --git a/HISTORY.rst b/HISTORY.rst
index af75ee84..4b25bb97 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -12,6 +12,11 @@ XXXX-XX-XX
on UNIX.
- XXXX_: Process.wait() return value is cached so that the exit code can be
retrieved on then next call.
+- XXXX_: Process provides more info about the process on str() and repr()
+ (status and exit code). Example:
+ >>> proc
+ psutil.Process(pid=12739, name='python3', status='terminated', exitcode=-9,
+ started='15:08:20')
**Bug fixes**
diff --git a/psutil/__init__.py b/psutil/__init__.py
index b03ffaee..411c6395 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -396,18 +396,22 @@ class Process(object):
except AttributeError:
info = {} # Python 2.6
info["pid"] = self.pid
+ if self._name:
+ info['name'] = self._name
with self.oneshot():
try:
info["name"] = self.name()
info["status"] = self.status()
- if self._create_time:
- info['started'] = _pprint_secs(self._create_time)
except ZombieProcess:
info["status"] = "zombie"
except NoSuchProcess:
info["status"] = "terminated"
except AccessDenied:
pass
+ if self._exitcode not in (_SENTINEL, None):
+ info["exitcode"] = self._exitcode
+ if self._create_time:
+ info['started'] = _pprint_secs(self._create_time)
return "%s.%s(%s)" % (
self.__class__.__module__,
self.__class__.__name__,
diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py
index ed06df77..ffb73f5b 100644
--- a/psutil/tests/__init__.py
+++ b/psutil/tests/__init__.py
@@ -874,17 +874,14 @@ class PsutilTestCase(TestCase):
self.addCleanup(terminate, sproc) # executed first
return sproc
- def assertPidGone(self, pid):
- assert not psutil.pid_exists(pid), pid
- self.assertNotIn(pid, psutil.pids())
-
def assertProcessGone(self, proc):
self.assertRaises(psutil.NoSuchProcess, psutil.Process, proc.pid)
if isinstance(proc, (psutil.Process, psutil.Popen)):
assert not proc.is_running()
self.assertRaises(psutil.NoSuchProcess, proc.status)
proc.wait(timeout=0) # assert not raise TimeoutExpired
- self.assertPidGone(proc.pid)
+ assert not psutil.pid_exists(proc.pid), proc.pid
+ self.assertNotIn(proc.pid, psutil.pids())
@unittest.skipIf(PYPY, "unreliable on PYPY")
diff --git a/psutil/tests/test_misc.py b/psutil/tests/test_misc.py
index 4fb8ba5a..959d12e5 100755
--- a/psutil/tests/test_misc.py
+++ b/psutil/tests/test_misc.py
@@ -57,20 +57,25 @@ import psutil.tests
class TestMisc(PsutilTestCase):
def test_process__repr__(self, func=repr):
- p = psutil.Process()
+ p = psutil.Process(self.spawn_testproc().pid)
r = func(p)
self.assertIn("psutil.Process", r)
self.assertIn("pid=%s" % p.pid, r)
- self.assertIn("name=", r)
+ self.assertIn("name='%s'" % p.name(), r)
self.assertIn("status=", r)
- self.assertIn(p.name(), r)
- self.assertIn("status='running'", r)
+ self.assertNotIn("exitcode=", r)
+ p.terminate()
+ code = p.wait()
+ r = func(p)
+ self.assertIn("status='terminated'", r)
+ self.assertIn("exitcode=%s" % code, r)
+
with mock.patch.object(psutil.Process, "name",
side_effect=psutil.ZombieProcess(os.getpid())):
p = psutil.Process()
r = func(p)
self.assertIn("pid=%s" % p.pid, r)
- self.assertIn("zombie", r)
+ self.assertIn("status='zombie'", r)
self.assertNotIn("name=", r)
with mock.patch.object(psutil.Process, "name",
side_effect=psutil.NoSuchProcess(os.getpid())):
@@ -303,7 +308,10 @@ class TestMisc(PsutilTestCase):
else:
with self.assertRaises(Exception):
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- sock.bind(("::1", 0))
+ try:
+ sock.bind(("::1", 0))
+ finally:
+ sock.close()
def test_isfile_strict(self):
from psutil._common import isfile_strict