Skip to content

Commit

Permalink
fix #2238 if cwd() cannot be determined always return "" instead of None
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo committed Apr 16, 2023
1 parent b070015 commit 0e3f6c4
Show file tree
Hide file tree
Showing 9 changed files with 34 additions and 27 deletions.
8 changes: 6 additions & 2 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
empty string)
- The function is faster since it no longer iterates over all processes.
- No longer produces duplicate connection entries.
- 2238_: there are cases where `Process.cwd()`_ cannot be determined
(e.g. directory no longer exists), in which case we returned either ``None``
or an empty string. This was consolidated and we now return ``""`` on all
platforms.

**Bug fixes**

Expand All @@ -39,8 +43,8 @@
*used* are too high. We now match values shown by *htop* CLI utility.
- 2236_, [NetBSD]: `Process.num_threads()`_ and `Process.threads()`_ return
threads that are already terminated.
- 2237_, [OpenBSD]: `Process.cwd()`_ may raise ``FileNotFoundError`` if cwd no
longer exists. Return ``None`` instead.
- 2237_, [OpenBSD], [NetBSD]: `Process.cwd()`_ may raise ``FileNotFoundError``
if cwd no longer exists. Return an empty string instead.

5.9.4
=====
Expand Down
11 changes: 7 additions & 4 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1180,9 +1180,10 @@ Process class

.. method:: exe()

The process executable as an absolute path.
On some systems this may also be an empty string.
The return value is cached after first call.
The process executable as an absolute path. On some systems, if exe cannot
be determined for some internal reason (e.g. system process or path no
longer exists), this may be an empty string. The return value is cached
after first call.

>>> import psutil
>>> psutil.Process().exe()
Expand Down Expand Up @@ -1281,7 +1282,9 @@ Process class

.. method:: cwd()

The process current working directory as an absolute path.
The process current working directory as an absolute path. If cwd cannot be
determined for some internal reason (e.g. system process or directiory no
longer exists) it may return an empty string.

.. versionchanged:: 5.6.4 added support for NetBSD

Expand Down
2 changes: 1 addition & 1 deletion psutil/_psaix.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ def cwd(self):
return result.rstrip('/')
except FileNotFoundError:
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
return None
return ""

@wrap_exceptions
def memory_info(self):
Expand Down
2 changes: 1 addition & 1 deletion psutil/_psbsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ def cwd(self):
elif NETBSD or HAS_PROC_OPEN_FILES:
# FreeBSD < 8 does not support functions based on
# kinfo_getfile() and kinfo_getvmmap()
return cext.proc_cwd(self.pid) or None
return cext.proc_cwd(self.pid) or ""
else:
raise NotImplementedError(
"supported only starting from FreeBSD 8" if
Expand Down
2 changes: 1 addition & 1 deletion psutil/_pssunos.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ def cwd(self):
return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid))
except FileNotFoundError:
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
return None
return ""

@wrap_exceptions
def memory_info(self):
Expand Down
9 changes: 6 additions & 3 deletions psutil/arch/netbsd/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,13 @@ psutil_proc_cwd(PyObject *self, PyObject *args) {
ssize_t len = readlink(buf, path, sizeof(path) - 1);
free(buf);
if (len == -1) {
if (errno == ENOENT)
NoSuchProcess("readlink -> ENOENT");
else
if (errno == ENOENT) {
psutil_debug("sysctl(KERN_PROC_CWD) -> ENOENT converted to ''");
return Py_BuildValue("", "");
}
else {
PyErr_SetFromErrno(PyExc_OSError);
}
return NULL;
}
path[len] = '\0';
Expand Down
4 changes: 2 additions & 2 deletions psutil/arch/openbsd/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,8 @@ psutil_proc_cwd(PyObject *self, PyObject *args) {
int name[] = { CTL_KERN, KERN_PROC_CWD, pid };
if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) {
if (errno == ENOENT) {
psutil_debug("sysctl(KERN_PROC_CWD) -> ENOENT converted to None");
Py_RETURN_NONE; // mimic os.cpu_count()
psutil_debug("sysctl(KERN_PROC_CWD) -> ENOENT converted to ''");
return Py_BuildValue("", "");
}
else {
PyErr_SetFromErrno(PyExc_OSError);
Expand Down
16 changes: 9 additions & 7 deletions psutil/tests/test_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,9 @@ def cmdline(self, ret, info):
self.assertIsInstance(part, str)

def exe(self, ret, info):
self.assertIsInstance(ret, (str, unicode, type(None)))
if not ret:
self.assertEqual(ret, '')
else:
self.assertIsInstance(ret, (str, unicode))
self.assertEqual(ret.strip(), ret)
if ret:
if WINDOWS and not ret.endswith('.exe'):
return # May be "Registry", "MemCompression", ...
assert os.path.isabs(ret), ret
Expand Down Expand Up @@ -520,7 +519,8 @@ def gids(self, ret, info):

def username(self, ret, info):
self.assertIsInstance(ret, str)
assert ret
self.assertEqual(ret.strip(), ret)
assert ret.strip()

def status(self, ret, info):
self.assertIsInstance(ret, str)
Expand Down Expand Up @@ -619,6 +619,7 @@ def open_files(self, ret, info):
for f in ret:
self.assertIsInstance(f.fd, int)
self.assertIsInstance(f.path, str)
self.assertEqual(f.path.strip(), f.path)
if WINDOWS:
self.assertEqual(f.fd, -1)
elif LINUX:
Expand Down Expand Up @@ -651,8 +652,9 @@ def connections(self, ret, info):
check_connection_ntuple(conn)

def cwd(self, ret, info):
if ret: # 'ret' can be None or empty
self.assertIsInstance(ret, str)
self.assertIsInstance(ret, (str, unicode))
self.assertEqual(ret.strip(), ret)
if ret:
assert os.path.isabs(ret), ret
try:
st = os.stat(ret)
Expand Down
7 changes: 1 addition & 6 deletions psutil/tests/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,7 @@ def test_users(self):
self.assertEqual(u.name, users[idx])
self.assertEqual(u.terminal, terminals[idx])
if u.pid is not None: # None on OpenBSD
p = psutil.Process(u.pid)
# on macOS time is off by ~47 secs for some reason, but
# the next test against 'who' CLI succeeds
delta = 60 if MACOS else 1
self.assertAlmostEqual(
u.started, p.create_time(), delta=delta)
psutil.Process(u.pid)

@retry_on_failure()
def test_users_started(self):
Expand Down

0 comments on commit 0e3f6c4

Please sign in to comment.