Skip to content

Commit

Permalink
#650: make cmdline() handle unicode on python 2
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo committed Aug 26, 2015
1 parent d592453 commit b9823db
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 42 deletions.
4 changes: 4 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,10 @@ Process class

The command line this process has been called with.

*Changed in 3.2.0:* (Windows, Python 2) in case one or more parts of the
cmdline contains non ASCII characters the returned type is a list of
unicode strings.

.. method:: create_time()

The process creation time as a floating point number expressed in seconds
Expand Down
15 changes: 14 additions & 1 deletion psutil/_pswindows.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,20 @@ def exe(self):

@wrap_exceptions
def cmdline(self):
return cext.proc_cmdline(self.pid)
ret = cext.proc_cmdline(self.pid)
if PY3:
return ret
else:
# On Python 2, if one or more bits of the cmdline is unicode
# we return a list of unicode strings.
new = []
for x in ret:
x = py2_stringify(x)
if isinstance(x, unicode):
return ret
else:
new.append(x)
return new

def ppid(self):
try:
Expand Down
55 changes: 16 additions & 39 deletions psutil/arch/windows/process_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,8 @@ psutil_get_arg_list(long pid) {
PVOID rtlUserProcParamsAddress;
UNICODE_STRING commandLine;
WCHAR *commandLineContents = NULL;
PyObject *arg = NULL;
PyObject *arg_from_wchar = NULL;
PyObject *argList = NULL;
PyObject *py_arg = NULL;
PyObject *py_retlist = NULL;

hProcess = psutil_handle_from_pid(pid);
if (hProcess == NULL)
Expand Down Expand Up @@ -274,61 +273,39 @@ psutil_get_arg_list(long pid) {
// commandLine.Length is in bytes.
commandLineContents[(commandLine.Length / sizeof(WCHAR))] = '\0';

// attempt tp parse the command line using Win32 API, fall back
// attempt to parse the command line using Win32 API, fall back
// on string cmdline version otherwise
szArglist = CommandLineToArgvW(commandLineContents, &nArgs);
if (NULL == szArglist) {
// failed to parse arglist
// encode as a UTF8 Python string object from WCHAR string
arg_from_wchar = PyUnicode_FromWideChar(commandLineContents,
commandLine.Length / 2);
if (arg_from_wchar == NULL)
goto error;
#if PY_MAJOR_VERSION >= 3
argList = Py_BuildValue("N", PyUnicode_AsUTF8String(arg_from_wchar));
#else
argList = Py_BuildValue("N", PyUnicode_FromObject(arg_from_wchar));
#endif
if (!argList)
goto error;
if (szArglist == NULL) {
PyErr_SetFromWindowsErr(0);
goto error;
}
else {
// arglist parsed as array of UNICODE_STRING, so convert each to
// Python string object and add to arg list
argList = Py_BuildValue("[]");
if (argList == NULL)
py_retlist = Py_BuildValue("[]");
if (py_retlist == NULL)
goto error;
for (i = 0; i < nArgs; i++) {
arg_from_wchar = NULL;
arg = NULL;
arg_from_wchar = PyUnicode_FromWideChar(szArglist[i],
wcslen(szArglist[i]));
if (arg_from_wchar == NULL)
goto error;
#if PY_MAJOR_VERSION >= 3
arg = PyUnicode_FromObject(arg_from_wchar);
#else
arg = PyUnicode_AsUTF8String(arg_from_wchar);
#endif
if (arg == NULL)
py_arg = PyUnicode_FromWideChar(
szArglist[i], wcslen(szArglist[i]));
if (py_arg == NULL)
goto error;
Py_XDECREF(arg_from_wchar);
if (PyList_Append(argList, arg))
if (PyList_Append(py_retlist, py_arg))
goto error;
Py_XDECREF(arg);
Py_XDECREF(py_arg);
}
}

if (szArglist != NULL)
LocalFree(szArglist);
free(commandLineContents);
CloseHandle(hProcess);
return argList;
return py_retlist;

error:
Py_XDECREF(arg);
Py_XDECREF(arg_from_wchar);
Py_XDECREF(argList);
Py_XDECREF(py_arg);
Py_XDECREF(py_retlist);
if (hProcess != NULL)
CloseHandle(hProcess);
if (commandLineContents != NULL)
Expand Down
6 changes: 4 additions & 2 deletions test/_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,8 +491,10 @@ def test_proc_cmdline(self):
shutil.copyfile(sys.executable, self.uexe)
subp = get_test_subprocess(cmd=[self.uexe])
p = psutil.Process(subp.pid)
self.assertIsInstance("".join(p.cmdline()), unicode)
self.assertEqual(p.cmdline(), [self.uexe])
self.assertIsInstance(u("").join(p.cmdline()), unicode)
uexe = self.uexe if PY3 else \
unicode(self.uexe, sys.getfilesystemencoding())
self.assertEqual(p.cmdline(), [uexe])

def test_proc_cwd(self):
tdir = tempfile.mkdtemp(prefix=u("psutil-è-"))
Expand Down

0 comments on commit b9823db

Please sign in to comment.