[Pymoul-svn] SF.net SVN: pymoul: [205] pymoul/trunk
Status: Alpha
Brought to you by:
tiran
From: <ti...@us...> - 2007-02-27 14:46:02
|
Revision: 205 http://pymoul.svn.sourceforge.net/pymoul/?rev=205&view=rev Author: tiran Date: 2007-02-27 06:45:53 -0800 (Tue, 27 Feb 2007) Log Message: ----------- Moved processinfo to external module Modified Paths: -------------- pymoul/trunk/INSTALL.txt pymoul/trunk/setup.py pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/osdependent/darwin/__init__.py pymoul/trunk/src/moul/osdependent/linux/__init__.py pymoul/trunk/src/moul/osdependent/win32/__init__.py Removed Paths: ------------- pymoul/trunk/src/moul/osdependent/processinfo.py Modified: pymoul/trunk/INSTALL.txt =================================================================== --- pymoul/trunk/INSTALL.txt 2007-02-27 14:32:21 UTC (rev 204) +++ pymoul/trunk/INSTALL.txt 2007-02-27 14:45:53 UTC (rev 205) @@ -4,9 +4,10 @@ * Python 2.5.x http://www.python.org/ * easy_install http://peak.telecommunity.com/DevCenter/EasyInstall - * setuptools (via easy install) - * PyTz (via $ easy_install-2.5 -Z pytz) - * Qt4 GPL 4.2+ http://www.trolltech.com/developer/downloads/qt/ + * setuptools (via easy_install) + * pytz (via $ easy_install-2.5 -Z pytz) + * enumprocess (via $ easy_install-2.5 -Z enumprocess) + * Qt4 GPL 4.2+ http://www.trolltech.com/developer/downloads/qt/ * PyQt4 4.1.1+ http://www.riverbankcomputing.co.uk/pyqt/ Windows Modified: pymoul/trunk/setup.py =================================================================== --- pymoul/trunk/setup.py 2007-02-27 14:32:21 UTC (rev 204) +++ pymoul/trunk/setup.py 2007-02-27 14:45:53 UTC (rev 205) @@ -57,7 +57,7 @@ setup_options = dict( setup_requires = ["setuptools>="+SETUPTOOLS_VERSION,], - install_requires = ["pytz>=2006p",], + install_requires = ["pytz>=2006p", "enumprocess>=0.1"], data_files = [ ('docs', list(glob('*.txt'))), ('i18n', list(glob('src/moul/qt/i18n/pymoul_*.qm'))), Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-02-27 14:32:21 UTC (rev 204) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-02-27 14:45:53 UTC (rev 205) @@ -38,14 +38,20 @@ import sys from types import ModuleType -from moul.osdependent.processinfo import getPidNames -from moul.osdependent.processinfo import getPids +# a program under py2exe is sys.frozen +__FROZEN__ = bool(getattr(sys, 'frozen', False)) +if not __FROZEN__: + import pkg_resources + pkg_resources.require("enumprocess>=0.1") +from enumprocess import getPidNames +from enumprocess import getPids + + LOG = getLogger('moul.osdependent') -# a program under py2exe is sys.frozen -__FROZEN__ = bool(getattr(sys, 'frozen', False)) + # OS stuff _plat = sys.platform.startswith __WIN32__ = _plat('win32') # win64, cygwin? Modified: pymoul/trunk/src/moul/osdependent/darwin/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-02-27 14:32:21 UTC (rev 204) +++ pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-02-27 14:45:53 UTC (rev 205) @@ -22,11 +22,11 @@ __revision__ = "$Revision$" import os +from logging import getLogger +from enumprocess import getPidNames from subprocess import Popen -from logging import getLogger - LOG = getLogger('moul.darwin') LOG.critical('Darwin/Mac support is not tested') Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-02-27 14:32:21 UTC (rev 204) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-02-27 14:45:53 UTC (rev 205) @@ -22,12 +22,11 @@ __revision__ = "$Revision$" import os +from logging import getLogger +from enumprocess import getPidNames from subprocess import Popen -from moul.osdependent.processinfo import getPidNames -from logging import getLogger - LOG = getLogger('moul.linux') LOG.critical('Linux support is not tested') Deleted: pymoul/trunk/src/moul/osdependent/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/processinfo.py 2007-02-27 14:32:21 UTC (rev 204) +++ pymoul/trunk/src/moul/osdependent/processinfo.py 2007-02-27 14:45:53 UTC (rev 205) @@ -1,465 +0,0 @@ -# pyMoul - Python interface to Myst Online URU Live -# Copyright (C) 2007 Christian Heimes <christian (at) cheimes (dot) de> - -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., 59 -# Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -"""Get process informations - -The module contains for implementations: - - - an Unsupported implementation that raises UnsupportedError - - a Linux implementation that read the data from /proc - - a Unix/POSIX implementation that parses the output of ps - - a Windows implementation that uses ctypes to get the infos from psapi.dll - -API -=== - getPids() - list of ints/longs - getPidNames() - mapping pid -> name - getPidDetails(pid) - detailed informations about a process - getPidDetails('self') - detailed informations about current process - ->>> cur = os.getpid() ->>> exe = sys.executable ->>> pids = getPids() ->>> pids > 1 -True ->>> isinstance(pids[0], (int, long)) -True ->>> cur in pids -True - ->>> mapping = getPidNames() ->>> cur in mapping -True ->>> mapping[cur].lower() in sys.executable -True - ->>> getPidDetails('self')['name'] == getPidDetails(cur)['name'] -True ->>> getPidDetails(cur)['name'] == mapping[cur] -True - ->>> for impl in (WinEnumProcesses(), LinuxProcReader(), PsParser()): -... if impl.supported(): -... isinstance(impl.getPids(), list) and None -... isinstance(impl.getPidNames(), dict) and None -""" -__author__ = "Christian Heimes" -__version__ = "$Id$" -__revision__ = "$Revision$" -__all__ = ['getPids', 'getPidNames', 'getPidDetails', 'supportedOS', - 'UnsupportedError'] - -import logging -import os -import os.path -import sys - - -LOG = logging.getLogger("processinfo") -NULL = "\x00" - -_plat = sys.platform.startswith -if _plat('win') or _plat('cygwin'): - from ctypes import windll, c_ulong, sizeof, c_buffer, byref - PSAPI = windll.psapi - KERNEL = windll.kernel32 - PROCESS_QUERY_INFORMATION = 0x0400 - PROCESS_VM_READ = 0x0010 - PROCESS_FLAGS = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ -else: - from subprocess import Popen - from subprocess import PIPE - -class UnsupportedError(OSError): - """OS or command not supported error - """ - pass - -class Unsupported(object): - """Unsupported OS implementation - - Raises L{UnsupportedError} - """ - __slots__ = () - - @classmethod - def supported(cls): - """Supported flag property""" - return False - - @classmethod - def log(cls): - """Log information about the implementation""" - LOG.warning("Unsupported OS. Neither proc filesystem nor 'ps' works.") - - @classmethod - def getPids(cls): - """Get a list of pids - - @return: a list of pid numbers - @rtype: list(int) - """ - raise UnsupportedError - - @classmethod - def getPidNames(cls): - """Get a mapping of pid -> name - - @return: mapping of pid -> name - @rtype: dict(int:str) - """ - raise UnsupportedError - - @classmethod - def getPidDetails(pid): - """Get detailed informations about a process - - @param pid: pid number or 'self' - @type pid: int or basestring - @return: detailed information about a process - @rtype: dict(str:data) - """ - raise UnsupportedError - -class PsParser(object): - """Parse the output of the ps command - """ - __slots__ = () - - CMD = "ps -e --no-header --cols=1024" - PIDNAMES = "%s --format=pid,ucmd" % CMD - PIDS = "%s --format=pid" % CMD - - @classmethod - def supported(cls): - """Supported flag property""" - try: - cls._exec(cls.PIDS) - except Exception: # catch all! - return False - else: - return True - - @classmethod - def log(cls): - """Log information about the implementation""" - LOG.debug("Using the 'ps' command on POSIX os") - - @classmethod - def getPids(cls): - """Get a list of pids - """ - stdout = cls._exec(cls.PIDS) - if stdout is None: - return None - pids = [] - for line in stdout: - try: - pid = int(line.strip()) - except ValueError: - pass - else: - pids.append(pid) - return pids - - @classmethod - def getPidNames(cls): - """Get a list of pid -> name - """ - stdout = cls._exec(cls.PIDNAMES) - if stdout is None: - return None - mapping = {} - for line in stdout: - line = line.strip() - idx = line.find(' ') - pid, name = line[:idx], line[idx+1:] - try: - pid = int(pid) - except ValueError: - pass - else: - mapping[pid] = name - return mapping - - @classmethod - def getPidDetails(cls, pid): - """Get detailed informations about a process - - TODO - """ - if pid == 'self': - pid = os.getpid() - raise UnsupportedError("not implemented yet") - - @staticmethod - def _exec(cmd): - """Execute command cmd - - The method waits until the command has finished. It returns None of - something went wrong. - - @param cmd: Command to execute - @type cmd: str - @return: None or stdin as file like object - """ - try: - popen = Popen(cmd, shell=True, bufsize=-1, stdout=PIPE, - env = {'LC_ALL' : 'C'}) - rc = popen.wait() - except (OSError, ValueError): - LOG.exception("Failed to execute '%s'" % cmd) - return None - else: - if rc != 0: - LOG.error("'%s' returned with error code %i" % (cmd, rc)) - return None - else: - return popen.stdout - -class LinuxProcReader(object): - """Get process informations under Linux by reading /proc - - Tested under Linux, may work on other POSIX os with /proc, too. - """ - __slots__ = () - - PROC = "/proc" - - @classmethod - def supported(cls): - return os.path.isfile("%s/self/status" % cls.PROC) - - @classmethod - def log(cls): - """Log information about the implementation""" - LOG.debug("Using the proc filesystem on Linux") - - @classmethod - def getPids(cls): - """Get a list of pids - """ - pids = [] - for name in os.listdir(cls.PROC): - if os.path.isdir(cls.PROC + '/' + name): - try: - pids.append(int(name)) - except ValueError: - pass - return pids - - @classmethod - def getPidNames(cls): - """Get a list of pid -> name - """ - mapping = {} - for pid in cls.getPids(): - name = cls._readProcStatus(pid, searchkey='name') - if name is not None: - mapping[pid] = name - return mapping - - def getPidDetails(cls, pid): - """Get detailed informations about a process - """ - details = cls._readProcStatus(pid) - if details is None: - return None - details.update(cls._readProcOther(pid)) - details['cmdline'] = cls._readProcCmdline(pid) - return details - - @classmethod - def _readProcStatus(cls, pid, searchkey=None): - """Read and parse status informations for PID pid - - pid - pid as long or int or 'self' - - If searchkey is None the method returns a mapping of lower keys - to values (stripped). - If searchkey is given than the method immediatly returns the value - or returns None if they key can't be found. - """ - mapping = {} - status = '%s/%s/status' % (cls.PROC, pid) - try: - # read entiry file to avoid race conditions - lines = open(status, 'r').readlines() - except IOError: - LOG.exception("%s not found" % status) - return None - for line in lines: - try: - key, value = line.split(':\t') - except ValueError: - continue - key = key.lower() - value = value.strip() - #if value.endswith(' kB'): - # value = value[:-3] - if key == searchkey: - return value - mapping[key.lower()] = value - if searchkey is not None: - return None - return mapping - - @classmethod - def _readProcCmdline(cls, pid): - """Read cmdline informations for pid and returns a list similar to sys.argv - """ - try: - # read entiry file to avoid race conditions - data = open('%s/%s/cmdline' % (cls.PROC, pid), 'r').read() - except IOError: - return None - return data.split(NULL) - - @classmethod - def _readProcOther(cls, pid): - """Read other possible useful things - - cwd -> current work directory (may not exist) - exe -> path to executable (may not exist) - """ - return { - 'cwd' : os.path.realpath('%s/%s/cwd' % (cls.PROC, pid)), - 'exe' : os.path.realpath('%s/%s/exe' % (cls.PROC, pid)), - } - -class WinEnumProcesses(object): - """""Get process informations under Win32 with psapi.dll - - Based on enumprocesses from Eric Koome - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/305279 - """ - __slots__ = () - - @classmethod - def supported(cls): - try: - cls.getPids() - except Exception: # catch all! - return False - else: - return True - - @classmethod - def log(cls): - """Log information about the implementation""" - LOG.debug("Using ctypes on Windows") - - @classmethod - def getPids(cls): - """Get a list of pids - """ - arr = c_ulong * 256 - lpidProcess = arr() - cb = sizeof(lpidProcess) - cbNeeded = c_ulong() - - # Call Enumprocesses to get hold of process id's - PSAPI.EnumProcesses(byref(lpidProcess), cb, byref(cbNeeded)) - nReturned = cbNeeded.value/sizeof(c_ulong()) # number of processes returned - return [pid for pid in lpidProcess][:nReturned] - - @classmethod - def getPidNames(cls): - """Get a list of pid -> name - """ - hModule = c_ulong() - count = c_ulong() - modname = c_buffer(51) - mapping = {} - for pid in cls.getPids(): - # Get handle to the process based on PID - hProcess = KERNEL.OpenProcess(PROCESS_FLAGS, False, pid) - if hProcess: - PSAPI.EnumProcessModules(hProcess, byref(hModule), - sizeof(hModule), byref(count)) - PSAPI.GetModuleBaseNameA(hProcess, hModule.value, modname, - sizeof(modname)) - try: - name = u"".join([c for c in modname if c != NULL]) - except UnicodeError, msg: - LOG.exception("Can't decode name of pid %s" % pid) - else: - mapping[pid] = name - modname[:] = sizeof(modname) * NULL - KERNEL.CloseHandle(hProcess) - - return mapping - - @classmethod - def getPidDetails(cls, pid): - """Get detailed informations about a process - """ - if pid == 'self': - pid = os.getpid() - - hModule = c_ulong() - count = c_ulong() - modname = c_buffer(51) - hProcess = KERNEL.OpenProcess(PROCESS_FLAGS, False, pid) - if not hProcess: - return None - - PSAPI.EnumProcessModules(hProcess, byref(hModule), - sizeof(hModule), byref(count)) - PSAPI.GetModuleBaseNameA(hProcess, hModule.value, modname, - sizeof(modname)) - try: - name = u"".join([c for c in modname if c != NULL]) - except UnicodeError, msg: - LOG.exception("Can't decode name of pid %s" % pid) - else: - name = None - - KERNEL.CloseHandle(hProcess) - return {'name' : name} - - -# Initialize global methods -_enumProcesses = None -for impl in (WinEnumProcesses(), LinuxProcReader(), PsParser()): - if impl.supported(): - impl.log() - _enumProcesses = impl - break - -if _enumProcesses is None: - LOG.error("System %s is not supported" % sys.platform) - _enumProcesses = Unsupported() - -getPids = _enumProcesses.getPids -getPidNames = _enumProcesses.getPidNames -getPidDetails = _enumProcesses.getPidDetails -supportedOS = _enumProcesses.supported() - -def test_suite(): - import unittest - from doctest import DocTestSuite - return unittest.TestSuite(( - DocTestSuite() - )) - -if __name__ == '__main__': - import unittest - logging.basicConfig() - unittest.main(defaultTest="test_suite") - print getPids() - print getPidNames() Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-02-27 14:32:21 UTC (rev 204) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-02-27 14:45:53 UTC (rev 205) @@ -22,10 +22,10 @@ __revision__ = "$Revision$" import os +from enumprocess import getPidNames +from logging import getLogger from subprocess import Popen -from logging import getLogger -from moul.osdependent.processinfo import getPidNames from moul.osdependent.win32 import winpath This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |