pymoul-svn Mailing List for pyMoul (Page 9)
Status: Alpha
Brought to you by:
tiran
You can subscribe to this list here.
2007 |
Jan
(89) |
Feb
(108) |
Mar
(62) |
Apr
(8) |
May
(9) |
Jun
(2) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
---|
From: <ti...@us...> - 2007-01-29 22:07:45
|
Revision: 99 http://pymoul.svn.sourceforge.net/pymoul/?rev=99&view=rev Author: tiran Date: 2007-01-29 14:07:42 -0800 (Mon, 29 Jan 2007) Log Message: ----------- First working implementation of log zipper and chatlog mover with unit tests Modified Paths: -------------- pymoul/trunk/Makefile.in pymoul/trunk/src/moul/file/chatlog.py pymoul/trunk/src/moul/file/plasmalog.py pymoul/trunk/src/moul/file/tests/test_plasmalog.py Modified: pymoul/trunk/Makefile.in =================================================================== --- pymoul/trunk/Makefile.in 2007-01-29 18:46:30 UTC (rev 98) +++ pymoul/trunk/Makefile.in 2007-01-29 22:07:42 UTC (rev 99) @@ -59,11 +59,12 @@ doc: doc_html clean: - find . \( -name '*.o' -o -name '*.c' -o -name '*.so' -o -name '*.py[cod]' -o -name '*.dll' \) -exec rm -f {} \; + find . \( -name '*.o' -o -name '*~' -o -name '*.so' -o -name '*.py[cod]' -o -name '*.dll' \) -exec rm -f {} \; rm -rf build realclean: clean rm -f TAGS + rm -rf dist $(PYTHON) setup.py clean -a propset: Modified: pymoul/trunk/src/moul/file/chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/chatlog.py 2007-01-29 18:46:30 UTC (rev 98) +++ pymoul/trunk/src/moul/file/chatlog.py 2007-01-29 22:07:42 UTC (rev 99) @@ -45,8 +45,8 @@ r"^\((?P<M>\d{1,2})/(?P<D>\d{1,2})\ " # MM/DD r"(?P<h>\d{1,2}):(?P<m>\d\d{1,2}):(?P<s>\d{1,2})\)" # hh:mm:ss r"(?P<space>\ {1,2})(?P<msg>.*)$") # text -CHAT_STARTED = "Chat.log started..." -CHAT_STOPPED = "...Chat.log stopped." +CHATLOG_STARTED = "Chat.log started..." +CHATLOG_STOPPED = "...Chat.log stopped." TEXT_MSGFROM = re.compile( r"From (?P<user>.*) in (?P<location>.*): (?P<msg>.*)" # From USER in LOCATION: msg @@ -76,17 +76,17 @@ """ """ _pat = "chat*.log" - _filename = "chatlog_%(sY)i%(sM)i%(sD)i_%(ch)i%(cm)i_%(sh)i%(sm)i.txt" + _filename = "chatlog_%(sY)02i%(sM)02i%(sD)02i_%(ch)02i%(cm)02i_%(sh)02i%(sm)02i.txt" def __init__(self, srcdir, destdir): - self._path = srcdir - self._dest = destdir - self._logs = [] - if not os.path.isdir(srcdir): - LOG.critical("%s is not a directory" % srcdir) - if not os.path.isdir(destdir): - LOG.info("Creating chatlog directory %s" % destdir) - os.mkdir(dest) + self._path = srcdir + self._dest = destdir + self._logs = [] + if not os.path.isdir(srcdir): + LOG.critical("%s is not a directory" % srcdir) + if not os.path.isdir(destdir): + LOG.info("Creating chatlog directory %s" % destdir) + os.mkdir(destdir) def findLogs(self): """Find log files in self._path @@ -95,7 +95,7 @@ for the file. """ for file in os.listdir(self._path): - if not fnmatch(file, self._pat): + if not fnmatch(file.lower(), self._pat): continue fpath = os.path.join(self._path, file) @@ -106,13 +106,13 @@ created = self._findCreated(fd) if not created: LOG.warning("Failed to parse chatlog %s" % fpath) - modtime = localtime(modtime(fpath)) - newname = self._makeFilename(created, modtime) + mtime = localtime(modtime(fpath)) + newname = self._makeFilename(created, mtime) details = { 'fpath' : fpath, 'filename' : file, - 'modtime' : localtime(modtime(fpath)), + 'modtime' : mtime, 'created' : created, 'newname' : newname, 'newpath' : os.path.join(self._dest, newname), @@ -132,8 +132,9 @@ if mo: data = mo.groupdict() if data['msg'].startswith(CHATLOG_STARTED): - created = (None, mo['M'], mo['D'], mo['h'], mo['m'], - mo['s'], None, None, None) + d = mo.groupdict() + created = (None, int(d['M']), int(d['D']), int(d['h']), + int(d['m']), int(d['s']), None, None, None) return created def _makeFilename(self, created, stopped): @@ -141,10 +142,10 @@ """ c, s = created, stopped mapping = { - 'sY' : s['Y'], 'sM' : s['YM'], 'sD' : s['D'], - 'sh' : s['h'], 'sm' : s['m'], 'ss' : s['s'], - 'cM' : c['YM'], 'cD' : c['D'], - 'ch' : c['h'], 'cm' : c['m'], 'cs' : c['s'], + 'sY' : s[0], 'sM' : s[1], 'sD' : s[2], + 'sh' : s[3], 'sm' : s[4], 'ss' : s[5], + 'cM' : c[1], 'cD' : c[2], + 'ch' : c[3], 'cm' : c[4], 'cs' : c[5], } return self._filename % mapping @@ -158,3 +159,7 @@ LOG.warning("%s exists - overwriting" % new) LOG.info("Move chatlog %s to %s" % (old, new)) move(old, new) + + def __call__(self): + self.findLogs() + self.moveChatlogs() Modified: pymoul/trunk/src/moul/file/plasmalog.py =================================================================== --- pymoul/trunk/src/moul/file/plasmalog.py 2007-01-29 18:46:30 UTC (rev 98) +++ pymoul/trunk/src/moul/file/plasmalog.py 2007-01-29 22:07:42 UTC (rev 99) @@ -28,8 +28,11 @@ from fnmatch import fnmatch from moul.crypt.elf import decryptElf +from moul.log import getLogger PLASMA_LOG = "plasmalog.txt" + +LOG = getLogger('moul.plasma') _marker = object() class PlasmalogZipper(object): @@ -40,38 +43,52 @@ def __init__(self, srcdir, destdir): self._srcdir = srcdir self._destdir = destdir + self._zipped_dirs = {} # dirname -> zipfile + self._not_removed = [] # files with full path - def getTimeStamp(self, path): + if not os.path.isdir(srcdir): + LOG.critical("%s is not a directory" % srcdir) + if not self.isPlasmaLogDir(): + self._ispldir = False + LOG.critical("%s is not a plasma log directory" % srcdir) + else: + self._ispldir = True + if not os.path.isdir(destdir): + LOG.info("Creating chatlog directory %s" % destdir) + os.mkdir(destdir) + + @staticmethod + def getTimeStamp(path): """Get time stamp yyyymmdd_hhmm based in the modification time """ sec = os.stat(path)[ST_MTIME] return time.strftime("%Y%m%d_%H%M", time.localtime(sec)) - - def isLogDir(self, path): + + def isPlasmaLogDir(self, path=None): """Check if a path is a valid plasma log directory - + Just checks for the plasmalog.txt file - Returns either False or a time stamp """ + if path is None: + path = self._srcdir pl = os.path.join(path, PLASMA_LOG) if not os.path.isfile(pl): return False - return getTimeStamp(pl) + return self.getTimeStamp(pl) def zipLogDir(self): """Zip all log files This function also zips subdirectories. """ - stored_dirs = [] - for root, dirs, files in os.walk(self._srcdir): - stamp = isLogDir(root) + stamp = self.isPlasmaLogDir(root) if not stamp: continue name = os.path.basename(root) zipname = "%s_%s.zip" % (name, stamp) + self._zipped_dirs[name] = zipname zipfd = zipfile.ZipFile(os.path.join(self._destdir, zipname), 'w', zipfile.ZIP_DEFLATED) for file in files: @@ -83,24 +100,27 @@ zipfd.write(fname, arcname) #zipfd.printdir() zipfd.close() - stored_dirs.append((root, zipname)) - return stored_dirs + def removeLogs(self): + """Removes log directories - def removeLogs(self, logdir): - """Removes log directories - The removeLogs function removes only files considered as safe """ - for root, dirs, files in os.walk(logdir, topdown=False): + for root, dirs, files in os.walk(self._srcdir, topdown=False): for name in files: matches = [pat for pat in self._save_patterns - if fnmatch(basename, pat)] - if match: - os.remove(os.path.join(root, name)) + if fnmatch(name, pat)] + fpath = os.path.join(root, name) + if matches: + os.remove(fpath) else: + self._not_removed.append(fpath) LOG.warning("Won't remove %s from %s" % (name, root)) for name in dirs: os.rmdir(os.path.join(root, name)) - os.rmdir(logdir) + os.rmdir(self._srcdir) + + def __call__(self): + self.zipLogDir() + self.removeLogs() Modified: pymoul/trunk/src/moul/file/tests/test_plasmalog.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-01-29 18:46:30 UTC (rev 98) +++ pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-01-29 22:07:42 UTC (rev 99) @@ -24,10 +24,102 @@ import unittest from doctest import DocTestSuite -import moul.file.plasmalog +import os +import shutil +from tempfile import mkdtemp +from moul.file.plasmalog import PlasmalogZipper +from moul.file.chatlog import ChatlogMover + +FILE_LIST = ['audio.0.elf', 'audiocaps.0.elf', 'audioTimes.0.elf', + 'Avatar.0.elf', 'impacts.0.elf', 'LocalizationDataMgr.0.elf', + 'Marker.0.elf', 'NetScreener.0.elf', 'patcher.0.elf', 'pipeline.0.elf', + 'plasmalog.txt', 'Python.0.elf', 'Simulation.0.elf', 'voice.0.elf', + 'Chat.0.log'] + +CHATLOG = """(01/02 03:04:05) Chat.log started... +(01/02 03:04:06) Testuser: foo +(01/02 03:04:07) ...Chat.log stopped. +""" + +base = os.path.dirname(__file__) + +def _fakeLogdir(path): + """Create a fake logdir + """ + if not os.path.isdir(path): + os.mkdir(path) + for fname in FILE_LIST: + fd = open(os.path.join(path, fname), 'w') + fd.write('dummy') + fd.close() + + fd = open(os.path.join(path, 'Chat.0.log'), 'w') + fd.write(CHATLOG) + fd.close() + fd = open(os.path.join(path, 'plasmalog.txt'), 'w') + fd.write('') + fd.close() + +def _fakeUruLiveDir(path): + """Create a fake Uru Live directory + """ + for dname in ('Avatars', 'init', 'KIimages'): + os.mkdir(os.path.join(path, dname)) + _fakeLogdir(os.path.join(path, 'Logs')) + _fakeLogdir(os.path.join(path, 'Logs', 'faketest')) + shutil.copyfile(os.path.join(base, 'avatar.jpg'), + os.path.join(path, 'Avatars', '001.jpg')) + shutil.copyfile(os.path.join(base, 'graphics.ini'), + os.path.join(path, 'init', 'graphics.ini')) + shutil.copyfile(os.path.join(base, 'audio.ini'), + os.path.join(path, 'init', 'audio.ini')) + +class PlasmaChatTest(unittest.TestCase): + def setUp(self): + self._tmpdir = mkdtemp() + self._chatdest = os.path.join(self._tmpdir, 'Chatlogs') + self._logdest = os.path.join(self._tmpdir, 'ZippedLogs') + self._logdir = os.path.join(self._tmpdir, 'Logs') + _fakeUruLiveDir(self._tmpdir) + self._clm = ChatlogMover(self._logdir, self._chatdest) + self._plz = PlasmalogZipper(self._logdir, self._logdest) + + def test_createDir(self): + self.failUnless(os.path.isdir(self._logdest), self._logdest) + self.failUnless(os.path.isdir(self._chatdest), self._chatdest) + + def test_plasmaLogZipper(self): + plz = self._plz + self.failUnless(plz.isPlasmaLogDir()) + plz.zipLogDir() + content = os.listdir(self._logdest) + content.sort() + self.failUnlessEqual(len(content), 2, content) + self.failUnless(content[0].startswith("Logs_"), content[0]) + self.failUnless(content[1].startswith("faketest_"), content[1]) + + plz.removeLogs() + self.failIf(os.path.isdir(self._logdir)) + + def test_chatLogMover(self): + clm = self._clm + clm.findLogs() + clm.moveChatlogs() + content = os.listdir(self._chatdest) + self.failUnlessEqual(len(content), 1, content) + length = len("chatlog_20070129_0304_2302.txt") + c = content[0] + self.failUnless(c.startswith("chatlog_")) + self.failUnless(c.endswith(".txt")) + self.failUnlessEqual(len(c), length, c) + + def tearDown(self): + shutil.rmtree(self._tmpdir) + def test_suite(): return unittest.TestSuite(( + unittest.makeSuite(PlasmaChatTest), DocTestSuite('moul.file.plasmalog') )) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-29 18:46:36
|
Revision: 98 http://pymoul.svn.sourceforge.net/pymoul/?rev=98&view=rev Author: tiran Date: 2007-01-29 10:46:30 -0800 (Mon, 29 Jan 2007) Log Message: ----------- Some work on chatlogs and plasma logs Modified Paths: -------------- pymoul/trunk/setup_win32.py pymoul/trunk/src/moul/file/chatlog.py pymoul/trunk/src/moul/file/plasmalog.py Modified: pymoul/trunk/setup_win32.py =================================================================== --- pymoul/trunk/setup_win32.py 2007-01-29 13:15:59 UTC (rev 97) +++ pymoul/trunk/setup_win32.py 2007-01-29 18:46:30 UTC (rev 98) @@ -78,8 +78,8 @@ pexe['upx_args'] = '--mono --best' # InnoSetup pexe['innosetup'] = os.environ.get('INNOSETUP') # TODO: + pexe['inno_templates'] = "template.iss" pexe['app_name'] = 'pyMoul' - # not required at the moment pexe['includes'].extend(findPyTz()) kw['zipfile'] = 'library.zip' Modified: pymoul/trunk/src/moul/file/chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/chatlog.py 2007-01-29 13:15:59 UTC (rev 97) +++ pymoul/trunk/src/moul/file/chatlog.py 2007-01-29 18:46:30 UTC (rev 98) @@ -16,6 +16,17 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # """Chat log parser + +Chatlog format +============== + +(MM/DD hh:mm:ss) Chat.log started... +(MM/DD hh:mm:ss) ...Chat.log stopped. +(MM/DD hh:mm:ss) From USER in LOCATION: msg +(MM/DD hh:mm:ss) Error: ERRORMSG +(MM/DD hh:mm:ss) USER: TEXT (note the two spaces!) +(MM/DD hh:mm:ss) To USER: TEXT +(MM/DD hh:mm:ss) USER action """ __author__ = "Christian Heimes" __version__ = "$Id$" @@ -23,22 +34,127 @@ import os import re -from glob import glob +from fnmatch import fnmatch +from stat import ST_MTIME +from shutil import move +from time import localtime -CHAT_RE_TXT = r"^\((?P<M>\d{1,2})/(?P<D>\d{1,2})\ " \ - r"(?P<h>\d{1,2}):(?P<m>\d\d{1,2}):(?P<s>\d{1,2})\)" \ - r"(?P<space>\ {1,2})(?P<text>.*)$" -CHAT_RE = re.compile(CHAT_RE_TXT) +from moul.log import getLogger +CHAT_RE = re.compile( + r"^\((?P<M>\d{1,2})/(?P<D>\d{1,2})\ " # MM/DD + r"(?P<h>\d{1,2}):(?P<m>\d\d{1,2}):(?P<s>\d{1,2})\)" # hh:mm:ss + r"(?P<space>\ {1,2})(?P<msg>.*)$") # text +CHAT_STARTED = "Chat.log started..." +CHAT_STOPPED = "...Chat.log stopped." +TEXT_MSGFROM = re.compile( + r"From (?P<user>.*) in (?P<location>.*): (?P<msg>.*)" + # From USER in LOCATION: msg + ) +TEXT_MSGTO = re.compile( + r"To (?P<user>.*): (?P<msg>.*)" + # From USER in LOCATION: msg + ) +TEXT_ERROR = re.compile( + r"Error: (?P<msg>.*)" + # Error: message + ) +TEXT = re.compile( + r"(?P<user>.*): (?P<msg>.*)" + # User: message + ) + + +LOG = getLogger('moul.chat') + +def modtime(pathname): + """Modification time + """ + return os.stat(pathname)[ST_MTIME] + class ChatlogMover(object): """ """ + _pat = "chat*.log" + _filename = "chatlog_%(sY)i%(sM)i%(sD)i_%(ch)i%(cm)i_%(sh)i%(sm)i.txt" - def __init__(self, path, dest): - self._path = path - self._dest = dest + def __init__(self, srcdir, destdir): + self._path = srcdir + self._dest = destdir self._logs = [] + if not os.path.isdir(srcdir): + LOG.critical("%s is not a directory" % srcdir) + if not os.path.isdir(destdir): + LOG.info("Creating chatlog directory %s" % destdir) + os.mkdir(dest) def findLogs(self): - self._logs.append(os.path.join(self._path, 'chat*.log')) + """Find log files in self._path + Also calls and stores _findCreated(), modtime() and _makeFile() + for the file. + """ + for file in os.listdir(self._path): + if not fnmatch(file, self._pat): + continue + + fpath = os.path.join(self._path, file) + if not os.path.isfile(fpath): + continue + LOG.debug("Found chatlog %s" % fpath) + fd = open(fpath, 'r') + created = self._findCreated(fd) + if not created: + LOG.warning("Failed to parse chatlog %s" % fpath) + modtime = localtime(modtime(fpath)) + newname = self._makeFilename(created, modtime) + + details = { + 'fpath' : fpath, + 'filename' : file, + 'modtime' : localtime(modtime(fpath)), + 'created' : created, + 'newname' : newname, + 'newpath' : os.path.join(self._dest, newname), + } + + self._logs.append(details) + + def _findCreated(self, fd): + """Parse chatlog to find "started" date + """ + created = None + while True: + line = fd.readline() + if not line: + break + mo = CHAT_RE.match(line) + if mo: + data = mo.groupdict() + if data['msg'].startswith(CHATLOG_STARTED): + created = (None, mo['M'], mo['D'], mo['h'], mo['m'], + mo['s'], None, None, None) + return created + + def _makeFilename(self, created, stopped): + """Build a filename from created and stopped information + """ + c, s = created, stopped + mapping = { + 'sY' : s['Y'], 'sM' : s['YM'], 'sD' : s['D'], + 'sh' : s['h'], 'sm' : s['m'], 'ss' : s['s'], + 'cM' : c['YM'], 'cD' : c['D'], + 'ch' : c['h'], 'cm' : c['m'], 'cs' : c['s'], + } + return self._filename % mapping + + def moveChatlogs(self): + """Move chatlogs from old to new location and name + """ + for details in self._logs: + old = details['fpath'] + new = details['newpath'] + if os.path.isfile(new): + LOG.warning("%s exists - overwriting" % new) + LOG.info("Move chatlog %s to %s" % (old, new)) + move(old, new) Modified: pymoul/trunk/src/moul/file/plasmalog.py =================================================================== --- pymoul/trunk/src/moul/file/plasmalog.py 2007-01-29 13:15:59 UTC (rev 97) +++ pymoul/trunk/src/moul/file/plasmalog.py 2007-01-29 18:46:30 UTC (rev 98) @@ -25,76 +25,82 @@ from stat import ST_MTIME import time import zipfile -import re +from fnmatch import fnmatch from moul.crypt.elf import decryptElf PLASMA_LOG = "plasmalog.txt" _marker = object() -RE_SAFEEXT_TEXT = "\.(elf|txt|log|zip|jpg|jpeg)$" -RE_SAFEXT = re.compile(RE_SAFEEXT_TEXT, re.IGNORECASE) -def getTimeStamp(path): - """Get time stamp yyyymmdd_hhmm based in the modification time +class PlasmalogZipper(object): + """Zip plasma logs """ - sec = os.stat(path)[ST_MTIME] - return time.strftime("%Y%m%d_%H%M", time.gmtime(sec)) + _save_patterns = ['*.elf', '*.txt', '*.log', '*.zip', '*.jpg'] + + def __init__(self, srcdir, destdir): + self._srcdir = srcdir + self._destdir = destdir -def isLogDir(path): - """Check if a path is a valid plasma log directory - - Just checks for the plasmalog.txt file - - Returns either False or a time stamp - """ - pl = os.path.join(path, PLASMA_LOG) - if not os.path.isfile(pl): - return False - return getTimeStamp(pl) - -def zipLogDir(logdir, destdir, remove): - """Zip all log files - - This function also zips subdirectories. - """ - stored_dirs = [] - - for root, dirs, files in os.walk(logdir): - stamp = isLogDir(root) - if not stamp: - continue - name = os.path.basename(root) - zipname = "%s_%s.zip" % (name, stamp) - zipfd = zipfile.ZipFile(os.path.join(destdir, zipname), - 'w', zipfile.ZIP_DEFLATED) - for file in files: - if file.lower().startswith('chat.'): - # omit chatlogs from the logs + def getTimeStamp(self, path): + """Get time stamp yyyymmdd_hhmm based in the modification time + """ + sec = os.stat(path)[ST_MTIME] + return time.strftime("%Y%m%d_%H%M", time.localtime(sec)) + + def isLogDir(self, path): + """Check if a path is a valid plasma log directory + + Just checks for the plasmalog.txt file + + Returns either False or a time stamp + """ + pl = os.path.join(path, PLASMA_LOG) + if not os.path.isfile(pl): + return False + return getTimeStamp(pl) + + def zipLogDir(self): + """Zip all log files + + This function also zips subdirectories. + """ + stored_dirs = [] + + for root, dirs, files in os.walk(self._srcdir): + stamp = isLogDir(root) + if not stamp: continue - fname = os.path.join(root, file) - arcname = os.path.join(name, file) - zipfd.write(fname, arcname) - #zipfd.printdir() - zipfd.close() - stored_dirs.append((root, zipname)) + name = os.path.basename(root) + zipname = "%s_%s.zip" % (name, stamp) + zipfd = zipfile.ZipFile(os.path.join(self._destdir, zipname), + 'w', zipfile.ZIP_DEFLATED) + for file in files: + if file.lower().startswith('chat.'): + # omit chatlogs from the logs + continue + fname = os.path.join(root, file) + arcname = os.path.join(name, file) + zipfd.write(fname, arcname) + #zipfd.printdir() + zipfd.close() + stored_dirs.append((root, zipname)) - if remove: - removeLogs(logdir) + return stored_dirs - return stored_dirs + def removeLogs(self, logdir): + """Removes log directories + + The removeLogs function removes only files considered as safe + """ + for root, dirs, files in os.walk(logdir, topdown=False): + for name in files: + matches = [pat for pat in self._save_patterns + if fnmatch(basename, pat)] + if match: + os.remove(os.path.join(root, name)) + else: + LOG.warning("Won't remove %s from %s" % (name, root)) + for name in dirs: + os.rmdir(os.path.join(root, name)) -def removeLogs(logdir): - """Removes log directories - - The removeLogs function removes only files considered as safe - """ - for root, dirs, files in os.walk(logdir, topdown=False): - for name in files: - if RE_SAFEXT.search(name): - os.remove(os.path.join(root, name)) - else: - print name # XXX - for name in dirs: - os.rmdir(os.path.join(root, name)) - - os.rmdir(logdir) + os.rmdir(logdir) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-29 13:16:05
|
Revision: 97 http://pymoul.svn.sourceforge.net/pymoul/?rev=97&view=rev Author: tiran Date: 2007-01-29 05:15:59 -0800 (Mon, 29 Jan 2007) Log Message: ----------- Added iss template Modified Paths: -------------- pymoul/trunk/distutils_iss.py Added Paths: ----------- pymoul/trunk/template.iss Modified: pymoul/trunk/distutils_iss.py =================================================================== --- pymoul/trunk/distutils_iss.py 2007-01-29 12:59:51 UTC (rev 96) +++ pymoul/trunk/distutils_iss.py 2007-01-29 13:15:59 UTC (rev 97) @@ -13,6 +13,7 @@ from ConfigParser import SafeConfigParser from ConfigParser import NoSectionError from ConfigParser import DEFAULTSECT +from string import ascii_letters class ISSConfigParser(SafeConfigParser): """Config parser with some extensions for ISS @@ -389,6 +390,9 @@ ip = interpolation.copy() ip['appname'] = appname ip['version'] = version + ip['appnamestripped'] = "".join([c for c in appname + if c in ascii_letters]) + ip['appexe'] = self.windows_exe_files[0] self.interpolation = ip self.cfg = ISSConfigParser(ip) @@ -425,7 +429,7 @@ self._writeLanguagesSect() self._writeWindowsExeFiles() self._writeLibFiles() - self._writeIcons() + #self._writeIcons() self._writeSections() def _writeLanguagesSect(self): Added: pymoul/trunk/template.iss =================================================================== --- pymoul/trunk/template.iss (rev 0) +++ pymoul/trunk/template.iss 2007-01-29 13:15:59 UTC (rev 97) @@ -0,0 +1,40 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +AppName=%(appname)s +AppVerName=%(appname)s %(version)s +AppPublisher=Christian Heimes +AppPublisherURL=http://www.cheimes.de/ +AppSupportURL=http://pymoul.sourceforge.net/ +AppUpdatesURL=http://sourceforge.net/projects/pymoul/ +DefaultDirName={pf}\%(appname)s +DefaultGroupName=%(appname)s +LicenseFile=GPL.txt +InfoBeforeFile=README.txt +;InfoAfterFile=c:\Programme\Inno Setup 5\license.txt +OutputDir=dist\ +OutputBaseFilename=setup_%(appnamestripped)s_%(version)s +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" +Name: "dutch"; MessagesFile: "compiler:Languages\Dutch.isl" +Name: "french"; MessagesFile: "compiler:Languages\French.isl" +Name: "german"; MessagesFile: "compiler:Languages\German.isl" +Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl" +Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked +Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Icons] +Name: "{group}\%(appname)s"; Filename: "{app}\%(appexe)s" +Name: "{group}\{cm:ProgramOnTheWeb,%(appname)s}"; Filename: "http://pymoul.sourceforge.net/" +Name: "{group}\{cm:UninstallProgram,%(appname)s}"; Filename: "{uninstallexe}" +Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\%(appname)s"; Filename: "{app}\%(appexe)"; Tasks: quicklaunchicon + +[Run] +Filename: "{app}%(appexe)s"; Description: "{cm:LaunchProgram,My Program}"; Flags: nowait postinstall skipifsilent Property changes on: pymoul/trunk/template.iss ___________________________________________________________________ Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-29 12:59:57
|
Revision: 96 http://pymoul.svn.sourceforge.net/pymoul/?rev=96&view=rev Author: tiran Date: 2007-01-29 04:59:51 -0800 (Mon, 29 Jan 2007) Log Message: ----------- Better InnoScript integration Modified Paths: -------------- pymoul/trunk/distutils_upx.py Added Paths: ----------- pymoul/trunk/distutils_iss.py Copied: pymoul/trunk/distutils_iss.py (from rev 95, pymoul/trunk/distutils_upx.py) =================================================================== --- pymoul/trunk/distutils_iss.py (rev 0) +++ pymoul/trunk/distutils_iss.py 2007-01-29 12:59:51 UTC (rev 96) @@ -0,0 +1,510 @@ +"""Distutils helper for creating and running InnoSetup Script files +""" +__author__ = "Christian Heimes" +__version__ = "$Id" +__revision__ = "$Revision$" + +import os +import sys +import re +from distutils import log +from fnmatch import fnmatch +from subprocess import call as subcall +from ConfigParser import SafeConfigParser +from ConfigParser import NoSectionError +from ConfigParser import DEFAULTSECT + +class ISSConfigParser(SafeConfigParser): + """Config parser with some extensions for ISS + + new methods: + add_header(string) - Adds comments to the header + set_raw(section, string) - Adds a raw entry to a section + add_sectionif(section) + setif(section, option, value) + + changed behavior: + doesn't write [default] section to file + interpolates "%(...)s" when writing to file + doesn't parse key: value + parses "Key: "value"; ..." to raw + writes sections in the order they are created + + >>> from StringIO import StringIO + >>> defaults = {'appname' : 'Test App'} + >>> cfg = ISSConfigParser(defaults) + >>> cfg.add_header("header") + + >>> cfg.add_section("testsection") + >>> cfg.set("testsection", "key", "value %(appname)s") + >>> cfg.set_raw("testsection", 'Rawline: "%(appname)s";') + + >>> out = StringIO() + >>> cfg.write(out) + >>> out.seek(0) + >>> data = out.read() + >>> print data + ; header + [testsection] + key = value Test App + Rawline: "Test App"; + <BLANKLINE> + + >>> template = StringIO(data) + >>> del cfg, out, data + >>> cfg = ISSConfigParser(defaults) + >>> cfg.readfp(template) + >>> cfg._sections + {'testsection': {'__name__': 'testsection', 'key': 'value Test App'}} + >>> cfg._raw + {'testsection': ['Rawline: "Test App";']} + + >>> out = StringIO() + >>> cfg.write(out) + >>> out.seek(0) + >>> data = out.read() + >>> print data + [testsection] + key = value Test App + Rawline: "Test App"; + <BLANKLINE> + + >>> + """ + def __init__(self, defaults=None): + SafeConfigParser.__init__(self, defaults) + self._raw = {} + self._header = [] + self._order = [] + + def add_header(self, value): + """Add a header comment + """ + self._header.append(value) + + def add_section(self, section): + """Create a new section in the configuration. + """ + SafeConfigParser.add_section(self, section) + self._raw[section]= [] + self._order.append(section) + + def add_sectionif(self, section): + """Create a new section in the configuration if section doesn't exist. + """ + if not self.has_section(section): + self.add_section(section) + return True + + def setif(self, section, option, value): + """Set section-option to value if option is not yet set + """ + if not self.has_option(section, option): + self.set(section, option, value) + return True + + def set_raw(self, section, raw): + """Add a raw string to a section + """ + try: + sec = self._raw[section] + except KeyError: + raise NoSectionError(section) + if isinstance(raw, (tuple, list)): + for r in raw: + sec.append(r) + else: + sec.append(raw) + + def get_raw(self, section, raw=False, vars=None): + """Get all raw lines as string for a given section. + + Interpolates %(var)s vars + """ + d = self._defaults.copy() + try: + d.update(self._sections[section]) + except KeyError: + if section != DEFAULTSECT: + raise NoSectionError(section) + # Update with the entry specific variables + if vars: + for key, value in vars.items(): + d[self.optionxform(key)] = value + try: + rawdata = "\n".join(self._raw[section]) + except KeyError: + return None + + if raw: + return rawdata + else: + return self._interpolate(section, "RAWDATA", rawdata, d) + + def optionxform(self, optionstr): + return optionstr + + def write(self, fp): + """Write an .ini-format representation of the configuration state.""" + for header in self._header: + fp.write("; %s\n" % header.replace('\n', '; \n')) + #if self._defaults: + # fp.write("[%s]\n" % DEFAULTSECT) + # for (key, value) in self._defaults.items(): + # fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t'))) + # fp.write("\n") + for section in self._order: + fp.write("[%s]\n" % section) + for key in self._sections[section]: + if key == "__name__": + continue + value = self.get(section, key, raw=False) + fp.write("%s = %s\n" % + (key, str(value).replace('\n', '\n\t'))) + rawdata = self.get_raw(section, raw=False) + if rawdata: + fp.write(rawdata) + fp.write("\n") + + def remove_section(self, section): + """Remove a file section.""" + existed = RawConfigParser.remove_section(self, section) + if existed: + del self._raw[section] + return existed + + OPTCRE = re.compile( + r'(?P<option>[^=\s][^=]*)' # very permissive! + r'\s*(?P<vi>[=])\s*' # any number of space/tab, + # followed by separator + # (either : or =), followed + # by any # space/tab + r'(?P<value>.*)$' # everything up to eol + ) + + RAWRE = re.compile( + r'^[A-Z][A-Za-z]*:\s?' # 'Name: ' + r'".*";' # '"value ...";' and + ) + + def _read(self, fp, fpname): + """Parse a sectioned setup file. + + From ConfigParser.RawConfigParser + """ + cursect = None # None, or a dictionary + curraw = None + optname = None + lineno = 0 + e = None # None, or an exception + while True: + line = fp.readline() + if not line: + break + lineno = lineno + 1 + # comment or blank line? + if line.strip() == '' or line[0] in '#;': + continue + if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR": + # no leading whitespace + continue + # continuation line? + if line[0].isspace() and cursect is not None and optname: + value = line.strip() + if value: + cursect[optname] = "%s\n%s" % (cursect[optname], value) + # a section header or option header? + else: + # is it a section header? + mo = self.SECTCRE.match(line) + if mo: + sectname = mo.group('header') + if sectname in self._sections: + cursect = self._sections[sectname] + curraw = self._raw[sectname] + elif sectname == DEFAULTSECT: + cursect = self._defaults + else: + cursect = {'__name__': sectname} + curraw = [] # new + self._order.append(sectname) # new + self._sections[sectname] = cursect + self._raw[sectname] = curraw # new + # So sections can't start with a continuation line + optname = None + # no section header in the file? + elif cursect is None: + raise MissingSectionHeaderError(fpname, lineno, line) + # an option line? + else: + mo = self.OPTCRE.match(line) + if mo: + optname, vi, optval = mo.group('option', 'vi', 'value') + if vi in ('=', ':') and ';' in optval: + # ';' is a comment delimiter only if it follows + # a spacing character + pos = optval.find(';') + if pos != -1 and optval[pos-1].isspace(): + optval = optval[:pos] + optval = optval.strip() + # allow empty values + if optval == '""': + optval = '' + optname = self.optionxform(optname.rstrip()) + cursect[optname] = optval + else: + mo = self.RAWRE.match(line) # new + if mo: + # found a InnoSetup raw line + curraw.append(line.strip()) + else: + # a non-fatal parsing error occurred. set up the + # exception but keep going. the exception will be + # raised at the end of the file and will contain a + # list of all bogus lines + if not e: + e = ParsingError(fpname) + e.append(lineno, repr(line)) + # if any parsing errors occurred, raise an exception + if e: + raise e + + +class InnoSetupCommandMixin: + """Mixin class class for a distutils command + + You have call initialize_options() and run() from your class! + + >>> from tempfile import mkstemp + >>> tmphdlr, tmpfile = mkstemp() + + >>> test = InnoSetupCommandMixin() + >>> test.initialize_options() + >>> test.app_name = "Test App" + >>> test.innosetup = True + >>> test.inno_script = tmpfile + >>> test.lib_dir = 'li', + >>> test.dist_dir = 'dist' + >>> test.windows_exe_files = [r'dist\\test.exe'] + >>> test.lib_files = [r'dist\\lib1', r'dist\\lib2'] + + >>> try: + ... test.run() + ... finally: + ... data = open(tmpfile).read() + ... os.unlink(tmpfile) + + #>>> print data + """ + def initialize_options(self): + self.app_name = '' + self.innosetup = False + self.inno_script = None + self.inno_version = "1.0" + self.inno_templates = None + self.inno_interpolation = {} + self.inno_sections = {} + self.inno_languages = [('nl', 'Dutch'), ('de', 'German'), + ('fr', 'French'), ('it', 'Italian'), + ('es', 'Spanish') + ] + + def run(self): + self._createInnoSetup() + + def _createInnoSetup(self): + if not self.innosetup: + return + + self._inno_script = InnoScript( + self.app_name, + self.lib_dir, + self.dist_dir, + self.windows_exe_files, + self.lib_files, + inno_script = self.inno_script, + templates = self.inno_templates, + interpolation = self.inno_interpolation, + sections = self.inno_sections, + languages = self.inno_languages) + + print "*** creating the inno setup script***" + self._inno_script.create() + print "*** compiling the inno setup script***" + try: + self._inno_script.compile() + except RuntimeError, msg: + print "Failed to create installer:\n%s" % msg + # Note: By default the final setup.exe will be in an Output subdirectory. + +class InnoScript: + """Based on py2exe/samples/extending/setup.py + + Requires http://www.jrsoftware.org + + appname - name of the app + lib_dir - internal + dist_dir - internal + windows_exe_files - internal + lib_files - internal + isscript=None - path to IS script output file + templates = None - list of template file names or single file + version = "1.0" - version string + interpolation - dict with additional %()s interpolation items + sections - dict with additional section informations + languages - list with languages tuples e.g. [('de', 'German')] + + sections = {'sectioname' : + {'key' : 'value', + 'RAW' : 'string or list with raw items' + } + } + + """ + def __init__(self, + appname, + lib_dir, + dist_dir, + windows_exe_files, + lib_files, + inno_script=None, + templates = None, + version = "1.0", + interpolation = {}, + sections = {}, + languages = [] + ): + self.lib_dir = lib_dir + self.dist_dir = dist_dir + if not self.dist_dir[-1] in "\\/": + self.dist_dir += "\\" + self.windows_exe_files = [self.chop(p) for p in windows_exe_files] + self.lib_files = [self.chop(p) for p in lib_files] + if inno_script is None: + self.inno_script = os.path.join(dist_dir, appname.replace(' ', '_')+'.iss') + else: + self.inno_script = inno_script + self.fd = open(self.inno_script, "w") + + ip = interpolation.copy() + ip['appname'] = appname + ip['version'] = version + self.interpolation = ip + + self.cfg = ISSConfigParser(ip) + if templates: + read = self.cfg.read(templates) + self.sections = sections + self.languages = languages + + def chop(self, pathname): + assert pathname.startswith(self.dist_dir) + return pathname[len(self.dist_dir):] + + def create(self): + """create Inno Script + """ + self.createInnoScript() + self.modifyInnoScript() + self.writeInnoScript() + + def createInnoScript(self): + """Create Inno Script cfg + """ + cfg = self.cfg + cfg.add_header("WARNING: This script has been created by py2exe. Changes to this script") + cfg.add_header("will be overwritten the next time py2exe is run!\n") + + cfg.add_sectionif("Setup") + # Setup + cfg.setif("Setup", "AppName", "%(appname)s") + cfg.setif("Setup", "AppVerName", "%(appname)s %(version)s") + cfg.setif("Setup", "DefaultDirName", "{pf}\%(appname)s") + cfg.setif("Setup", "DefaultGroupName", "%(appname)s") + + self._writeLanguagesSect() + self._writeWindowsExeFiles() + self._writeLibFiles() + self._writeIcons() + self._writeSections() + + def _writeLanguagesSect(self): + cfg = self.cfg + if not self.languages: + return + cfg.add_sectionif('Languages') + for key, lang in self.languages: + cfg.set_raw("Languages", + 'Name: "%s"; MessagesFile: "compiler:Languages\%s.isl"' % + (key, lang)) + + def _writeWindowsExeFiles(self): + cfg = self.cfg + cfg.add_sectionif("Files") + for path in self.windows_exe_files: + cfg.set_raw("Files", + r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' + % (path, os.path.dirname(path)) ) + + def _writeLibFiles(self): + cfg = self.cfg + cfg.add_sectionif("Files") + for path in self.lib_files: + cfg.set_raw("Files", + r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' + % (path, os.path.dirname(path)) ) + + def _writeIcons(self): + cfg = self.cfg + cfg.add_sectionif("Icons") + for path in self.windows_exe_files: + cfg.set_raw("Icons", + 'Name: "{group}\\%(appname)s"; Filename: "{app}\\' + path + '"') + cfg.set_raw("Icons", r'Name: "{group}\Uninstall %(appname)s"; Filename: "{uninstallexe}"') + + def _writeSections(self): + cfg = self.cfg + # Additional things in self.sections + for section in self.sections: + cfg.add_sectionif(section) + for key, value in self.sections[section].items(): + if key == "RAW": + cfg.set_raw(section, value) + else: + cfg.set(section, key, value) + + def modifyInnoScript(self): + """Hook + """ + pass + + def writeInnoScript(self): + """Write script to disk + """ + self.cfg.write(self.fd) + self.fd.close() + + def compile(self): + import ctypes + res = ctypes.windll.shell32.ShellExecuteA(0, "compile", + self.isscript, + None, + None, + 0) + if res < 32: + raise RuntimeError("ShellExecute failed, error %d" % res) + + def __call__(self): + self.create() + self.compile() + +def test_suite(): + import unittest + from doctest import DocTestSuite + return unittest.TestSuite(( + DocTestSuite(__name__), + )) + +if __name__ == '__main__': + import unittest + unittest.main(defaultTest="test_suite") Modified: pymoul/trunk/distutils_upx.py =================================================================== --- pymoul/trunk/distutils_upx.py 2007-01-28 23:51:53 UTC (rev 95) +++ pymoul/trunk/distutils_upx.py 2007-01-29 12:59:51 UTC (rev 96) @@ -12,9 +12,9 @@ from distutils import log from stat import ST_SIZE from fnmatch import fnmatch -from ConfigParser import RawConfigParser +from distutils_iss import InnoSetupCommandMixin -class UpxCommand: +class UpxCommand(InnoSetupCommandMixin): """Upx packer mixin class for distutils Usage: @@ -36,6 +36,7 @@ def initialize_options(self): result = self._otherclass().initialize_options(self) + InnoSetupCommandMixin.initialize_options(self) self.upx = True self.upx_args = '--no-color' self.upx_path = 'upx' @@ -45,10 +46,6 @@ 'dylib', # Mac OS X ] self.upx_ignore = [] - - self.app_name = '' - self.innosetup = False - return result def finalize_options(self): @@ -65,7 +62,7 @@ def run(self, *args, **kwargs): result = self._otherclass().run(self, *args, **kwargs) self._upxPack() - self._createInnoSetup() + InnoSetupCommandMixin.run(self) return result def _upxPack(self): @@ -94,13 +91,13 @@ matches = [pat for pat in self.upx_ignore if fnmatch(basename, pat)] if matches: continue - + origsize = os.stat(fname)[ST_SIZE] self._upxPackFile(os.path.normpath(fname)) newsize = os.stat(fname)[ST_SIZE] ratio = newsize*100 / origsize packed.append((basename, origsize, newsize, ratio)) - + print "\n*** UPX result ***" for basename, origsize, newsize, ratio in packed: print " %s packed to %i%%" % (basename, ratio) @@ -147,186 +144,10 @@ Find next class in MRO that is not based on UpxCommand class """ for c in getmro(cls): - if not issubclass(c, UpxCommand): + if not issubclass(c, (UpxCommand, InnoSetupCommandMixin)): return c raise ValueError(cls) - def _createInnoSetup(self): - if not self.innosetup: - return - - script = InnoScript(self.app_name, - self.lib_dir, - self.dist_dir, - self.windows_exe_files, - self.lib_files) - print "*** creating the inno setup script***" - script.create() - print "*** compiling the inno setup script***" - try: - script.compile() - except RuntimeError, msg: - print "Failed to create installer:\n%s" % msg - # Note: By default the final setup.exe will be in an Output subdirectory. - -class InnoScript: - """Based on py2exe/samples/extending/setup.py - - Requires http://www.jrsoftware.org - """ - def __init__(self, - name, - lib_dir, - dist_dir, - windows_exe_files = [], - lib_files = [], - version = "1.0"): - self.lib_dir = lib_dir - self.dist_dir = dist_dir - # TODO: better name mangling - self.pathname = os.path.join(dist_dir, name.replace(' ', '_')+'.iss') - self.cfg = ISSConfigParser() - if not self.dist_dir[-1] in "\\/": - self.dist_dir += "\\" - self.name = name - self.version = version - self.windows_exe_files = [self.chop(p) for p in windows_exe_files] - self.lib_files = [self.chop(p) for p in lib_files] - self.setup_kwargs = { - } - self.languages = ["dutch", "french", "german", "italian", "spanish"] - - def chop(self, pathname): - assert pathname.startswith(self.dist_dir) - return pathname[len(self.dist_dir):] - - def create(self): - fd = self.file = open(self.pathname, "w") - cfg = self.cfg - cfg.add_header("; WARNING: This script has been created by py2exe. Changes to this script") - cfg.add_header("; will be overwritten the next time py2exe is run!\n") - cfg.add_section('Setup') - cfg.add_section('Files') - cfg.add_section('Icons') - cfg.add_section('Languages') - cfg.add_section('Tasks') - cfg.add_section('Run') - - # Setup - cfg.set("Setup", "AppName", self.name) - cfg.set("Setup", "AppVerName", "%s %s" % (self.name, self.version)) - cfg.set("Setup", "DefaultDirName", "{pf}\%s" % self.name) - cfg.set("Setup", "DefaultGroupName", self.name) - for key, value in self.setup_kwargs.items(): - cfg.set("Setup", key, value) - # Languages - cfg.set_raw('Languages', - 'Name: "english"; MessagesFile: "compiler:Default.isl"') - for lang in self.languages: - cfg.set_raw("Languages", - 'Name: "%s"; MessagesFile: "compiler:Languages/%s.isl"' - % (lang, lang.capitalize())) - - for path in self.windows_exe_files + self.lib_files: - cfg.set_raw("Files", - r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' - % (path, os.path.dirname(path)) - ) - for path in self.windows_exe_files: - cfg.set_raw("Icons", - 'Name: "{group}\%s"; Filename: "{app}\%s"' % - (self.name, path) - ) - cfg.set_raw("Icons", 'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name) - - def compile(self): - try: - import ctypes - except ImportError: - try: - import win32api - except ImportError: - import os - os.startfile(self.pathname) - else: - #print "Ok, using win32api." - win32api.ShellExecute(0, "compile", - self.pathname, - None, - None, - 0) - else: - #print "Cool, you have ctypes installed." - res = ctypes.windll.shell32.ShellExecuteA(0, "compile", - self.pathname, - None, - None, - 0) - if res < 32: - raise RuntimeError("ShellExecute failed, error %d" % res) - -class ISSConfigParser(RawConfigParser): - """Config parser for InnoSetupScripts - - Supports *only* writing and no parsing! - """ - def __init__(self, defaults=None): - RawConfigParser__init__(self, defaults) - self._raw = {} - self._header = [] - - def add_header(self, value): - """Add a header comment - """ - self._header.append(value) - - def add_section(self, section): - """Create a new section in the configuration. - """ - RawConfigParser.add_section(self, section) - self._raw[section]= [] - - def set_raw(self, section, raw): - """Add a raw string to a section - - TODO: use NoSectionError - """ - self._raw[section] = raw - - def _read(self, fp, fpname): - """Read and parse a filename or a list of filenames. - """ - raise NotImplementedError - - def optionxform(self, optionstr): - return optionstr - - def write(self, fp): - """Write an .ini-format representation of the configuration state.""" - for header in self._headers: - fp.write("; %s\n" % header.replace('\n', '; \n')) - if self._defaults: - fp.write("[%s]\n" % DEFAULTSECT) - for (key, value) in self._defaults.items(): - fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t'))) - fp.write("\n") - for section in self._sections: - fp.write("[%s]\n" % section) - for (key, value) in self._sections[section].items(): - if key != "__name__": - fp.write("%s = %s\n" % - (key, str(value).replace('\n', '\n\t'))) - for raw in self._raw['section']: - fp.write(str(raw).replace('\n', '\n\t') +'\n') - fp.write("\n") - - def remove_section(self, section): - """Remove a file section.""" - existed = RawConfigParser.remove_section(self, section) - if existed: - del self._raw[section] - return existed - try: from py2exe.build_exe import py2exe except ImportError: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-28 23:51:55
|
Revision: 95 http://pymoul.svn.sourceforge.net/pymoul/?rev=95&view=rev Author: tiran Date: 2007-01-28 15:51:53 -0800 (Sun, 28 Jan 2007) Log Message: ----------- Enhanced supported for IS script Modified Paths: -------------- pymoul/trunk/Makefile.in pymoul/trunk/distutils_upx.py Added Paths: ----------- pymoul/trunk/src/moul/qt/i18n/pymoul_nl.qm pymoul/trunk/src/moul/qt/i18n/pymoul_nl.ts Modified: pymoul/trunk/Makefile.in =================================================================== --- pymoul/trunk/Makefile.in 2007-01-28 21:14:23 UTC (rev 94) +++ pymoul/trunk/Makefile.in 2007-01-28 23:51:53 UTC (rev 95) @@ -6,7 +6,7 @@ FINDQT=find src/moul/qt \( -name '*.py' -o -name '*.ui' \) $(NOTSVN) FINDTEXT=find src/moul \( -name '*.py' -o -name '*.txt' -o -name '*.qrc' -o -name '*.ui' -o -name '*.ts' \) $(NOTSVN) FINDHASH= find . -not \( -name '*.txt' -o -name '*.asc' \) -a -not -type d -LANGS=de fr it es +LANGS=de es fr it nl TESTFLAGS=-v TESTOPTS= SETUPFLAGS= Modified: pymoul/trunk/distutils_upx.py =================================================================== --- pymoul/trunk/distutils_upx.py 2007-01-28 21:14:23 UTC (rev 94) +++ pymoul/trunk/distutils_upx.py 2007-01-28 23:51:53 UTC (rev 95) @@ -12,6 +12,7 @@ from distutils import log from stat import ST_SIZE from fnmatch import fnmatch +from ConfigParser import RawConfigParser class UpxCommand: """Upx packer mixin class for distutils @@ -184,38 +185,59 @@ self.dist_dir = dist_dir # TODO: better name mangling self.pathname = os.path.join(dist_dir, name.replace(' ', '_')+'.iss') + self.cfg = ISSConfigParser() if not self.dist_dir[-1] in "\\/": self.dist_dir += "\\" self.name = name self.version = version self.windows_exe_files = [self.chop(p) for p in windows_exe_files] self.lib_files = [self.chop(p) for p in lib_files] + self.setup_kwargs = { + } + self.languages = ["dutch", "french", "german", "italian", "spanish"] def chop(self, pathname): assert pathname.startswith(self.dist_dir) return pathname[len(self.dist_dir):] def create(self): - ofi = self.file = open(self.pathname, "w") - print >> ofi, "; WARNING: This script has been created by py2exe. Changes to this script" - print >> ofi, "; will be overwritten the next time py2exe is run!" - print >> ofi, r"[Setup]" - print >> ofi, r"AppName=%s" % self.name - print >> ofi, r"AppVerName=%s %s" % (self.name, self.version) - print >> ofi, r"DefaultDirName={pf}\%s" % self.name - print >> ofi, r"DefaultGroupName=%s" % self.name - print >> ofi - - print >> ofi, r"[Files]" + fd = self.file = open(self.pathname, "w") + cfg = self.cfg + cfg.add_header("; WARNING: This script has been created by py2exe. Changes to this script") + cfg.add_header("; will be overwritten the next time py2exe is run!\n") + cfg.add_section('Setup') + cfg.add_section('Files') + cfg.add_section('Icons') + cfg.add_section('Languages') + cfg.add_section('Tasks') + cfg.add_section('Run') + + # Setup + cfg.set("Setup", "AppName", self.name) + cfg.set("Setup", "AppVerName", "%s %s" % (self.name, self.version)) + cfg.set("Setup", "DefaultDirName", "{pf}\%s" % self.name) + cfg.set("Setup", "DefaultGroupName", self.name) + for key, value in self.setup_kwargs.items(): + cfg.set("Setup", key, value) + # Languages + cfg.set_raw('Languages', + 'Name: "english"; MessagesFile: "compiler:Default.isl"') + for lang in self.languages: + cfg.set_raw("Languages", + 'Name: "%s"; MessagesFile: "compiler:Languages/%s.isl"' + % (lang, lang.capitalize())) + for path in self.windows_exe_files + self.lib_files: - print >> ofi, r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' % (path, os.path.dirname(path)) - print >> ofi - - print >> ofi, r"[Icons]" + cfg.set_raw("Files", + r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' + % (path, os.path.dirname(path)) + ) for path in self.windows_exe_files: - print >> ofi, r'Name: "{group}\%s"; Filename: "{app}\%s"' % \ - (self.name, path) - print >> ofi, 'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name + cfg.set_raw("Icons", + 'Name: "{group}\%s"; Filename: "{app}\%s"' % + (self.name, path) + ) + cfg.set_raw("Icons", 'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name) def compile(self): try: @@ -243,7 +265,68 @@ if res < 32: raise RuntimeError("ShellExecute failed, error %d" % res) +class ISSConfigParser(RawConfigParser): + """Config parser for InnoSetupScripts + Supports *only* writing and no parsing! + """ + def __init__(self, defaults=None): + RawConfigParser__init__(self, defaults) + self._raw = {} + self._header = [] + + def add_header(self, value): + """Add a header comment + """ + self._header.append(value) + + def add_section(self, section): + """Create a new section in the configuration. + """ + RawConfigParser.add_section(self, section) + self._raw[section]= [] + + def set_raw(self, section, raw): + """Add a raw string to a section + + TODO: use NoSectionError + """ + self._raw[section] = raw + + def _read(self, fp, fpname): + """Read and parse a filename or a list of filenames. + """ + raise NotImplementedError + + def optionxform(self, optionstr): + return optionstr + + def write(self, fp): + """Write an .ini-format representation of the configuration state.""" + for header in self._headers: + fp.write("; %s\n" % header.replace('\n', '; \n')) + if self._defaults: + fp.write("[%s]\n" % DEFAULTSECT) + for (key, value) in self._defaults.items(): + fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t'))) + fp.write("\n") + for section in self._sections: + fp.write("[%s]\n" % section) + for (key, value) in self._sections[section].items(): + if key != "__name__": + fp.write("%s = %s\n" % + (key, str(value).replace('\n', '\n\t'))) + for raw in self._raw['section']: + fp.write(str(raw).replace('\n', '\n\t') +'\n') + fp.write("\n") + + def remove_section(self, section): + """Remove a file section.""" + existed = RawConfigParser.remove_section(self, section) + if existed: + del self._raw[section] + return existed + try: from py2exe.build_exe import py2exe except ImportError: Added: pymoul/trunk/src/moul/qt/i18n/pymoul_nl.qm =================================================================== (Binary files differ) Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_nl.qm ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: pymoul/trunk/src/moul/qt/i18n/pymoul_nl.ts =================================================================== --- pymoul/trunk/src/moul/qt/i18n/pymoul_nl.ts (rev 0) +++ pymoul/trunk/src/moul/qt/i18n/pymoul_nl.ts 2007-01-28 23:51:53 UTC (rev 95) @@ -0,0 +1,248 @@ +<!DOCTYPE TS><TS> +<context> + <name>MainWindow</name> + <message> + <source>Tool for Myst Online</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Configure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Windowed</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Vertical Sync</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Display Shadows</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Screen Resolution</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>800x600 (4:3)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Texture Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Low</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>High</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anti-Aliasing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Med.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ultra</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Shadow Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anisotropic-Filtering</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPC Voices</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound FX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ambience Sound</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Mute all</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hardware</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio Modes</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Generic Software</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable EAX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Voice chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Microphon Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable Voice Chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time zones</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cavern time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cyan time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>UTC -0</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Mountain Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Pacific Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>D'ni time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping</source> + <translation type="unfinished"></translation> + </message> + <message> + <source><html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal; text-decoration:none;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Browse in game documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Age</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Element</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Set</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>pyMoul tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>About</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is not running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Not Implemented</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sorry, this feature is not implemented yet!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening graphics.ini</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening audio.ini</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_nl.ts ___________________________________________________________________ Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-28 21:14:22
|
Revision: 94 http://pymoul.svn.sourceforge.net/pymoul/?rev=94&view=rev Author: tiran Date: 2007-01-28 13:14:23 -0800 (Sun, 28 Jan 2007) Log Message: ----------- include more files in dist Added hash stuff Modified Paths: -------------- pymoul/trunk/Makefile.in pymoul/trunk/compileui.py pymoul/trunk/setup.py Modified: pymoul/trunk/Makefile.in =================================================================== --- pymoul/trunk/Makefile.in 2007-01-28 17:15:47 UTC (rev 93) +++ pymoul/trunk/Makefile.in 2007-01-28 21:14:23 UTC (rev 94) @@ -4,7 +4,8 @@ FINDPYTXT=find src/moul \( -name '*.py' -o -name '*.txt' \) $(NOTSVN) FINDPY=find src/moul -name '*.py' $(NOTSVN) FINDQT=find src/moul/qt \( -name '*.py' -o -name '*.ui' \) $(NOTSVN) -FINDTEXT=find src/moul \( -name '*.py' -o -name '*.txt' -o -name '*.qrc' -o -name '*.ui' -o -name '*.ts' \) $(NOTSVN) +FINDTEXT=find src/moul \( -name '*.py' -o -name '*.txt' -o -name '*.qrc' -o -name '*.ui' -o -name '*.ts' \) $(NOTSVN) +FINDHASH= find . -not \( -name '*.txt' -o -name '*.asc' \) -a -not -type d LANGS=de fr it es TESTFLAGS=-v TESTOPTS= @@ -78,3 +79,9 @@ lrelease src/moul/qt/i18n/pymoul_$${L}.ts; \ done +hash: + cd dist && $(FINDHASH) | xargs md5sum >md5.txt + cd dist && $(FINDHASH) | xargs sha1sum >sha1.txt + cd dist && $(FINDHASH) | xargs gpg --detach-sign -a + + Modified: pymoul/trunk/compileui.py =================================================================== --- pymoul/trunk/compileui.py 2007-01-28 17:15:47 UTC (rev 93) +++ pymoul/trunk/compileui.py 2007-01-28 21:14:23 UTC (rev 94) @@ -11,7 +11,7 @@ from PyQt4 import uic -RE_RC_TEXT = "^import\ (?P<module>[a-zA-Z]\w*_rc)\s$" +RE_RC_TEXT = "^import[ \.\\/]*(?P<module>[a-zA-Z]\w*_rc)\s$" RE_RC = re.compile(RE_RC_TEXT) UI_EXT = '.ui' @@ -19,7 +19,7 @@ QRC_EXT = '.qrc' PY_QRC_EXT = '_rc.py' QRC_COMPILER = "pyrcc4 -o %(py)s %(qrc)s" -UI_MODULE = "moul.qt.ui" +QRC_PACKAGE = "moul.qt.ui" def _newer(orig, py): try: @@ -81,7 +81,7 @@ # faster than re match = RE_RC.match(line) if match: - line = match.expand("from %s import \g<module>" % UI_MODULE) + line = match.expand("from %s import \g<module>" % QRC_PACKAGE) lines.append(line) fin.close() fout = open(fname, 'w') Modified: pymoul/trunk/setup.py =================================================================== --- pymoul/trunk/setup.py 2007-01-28 17:15:47 UTC (rev 93) +++ pymoul/trunk/setup.py 2007-01-28 21:14:23 UTC (rev 94) @@ -58,7 +58,10 @@ setup_options = dict( setup_requires = ["setuptools>="+SETUPTOOLS_VERSION,], install_requires = [], - data_files = list(glob('*.txt')), + data_files = [ + ('docs', list(glob('*.txt'))), + ('i18', list(glob('src/moul/qt/i18n/pymoul_*.*'))), + ], package_dir = {'' : 'src'}, packages = find_packages('src', exclude="moul.qt"), include_package_data = True, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-28 17:15:46
|
Revision: 93 http://pymoul.svn.sourceforge.net/pymoul/?rev=93&view=rev Author: tiran Date: 2007-01-28 09:15:47 -0800 (Sun, 28 Jan 2007) Log Message: ----------- Changed log level Modified Paths: -------------- pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/ui/moulqt_rc.py Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-01-28 17:15:47 UTC (rev 93) @@ -369,7 +369,7 @@ self.clear() if isinstance(fd_name, basestring): fd = open(fd_name, 'rb') - LOG.debug("Parsing encrypted file %s" % fd_name) + LOG.info("Parsing encrypted file %s" % fd_name) close = True else: fd = fd_name @@ -514,7 +514,7 @@ # check for OpenAL device name = self._get('Audio.SetDeviceName') if name not in self._devices: - LOG.debug("Device added: %s" % name) + LOG.info("Device added: %s" % name) self._devices.append(name) def getDeviceIdx(self, name): Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/log.py 2007-01-28 17:15:47 UTC (rev 93) @@ -84,7 +84,7 @@ global fhdlr from moul.config import getPyMoulDataDir logFile = os.path.join(getPyMoulDataDir(check=True), 'pymoul.log') - LOG.debug("Adding file logger: %s" % logFile) + LOG.info("Adding file logger: %s" % logFile) fhdlr = handlers.RotatingFileHandler(logFile, backupCount=9) fhdlr.setFormatter(format) root.addHandler(fhdlr) @@ -92,15 +92,15 @@ def _systemInfo(): from moul.osdependent import __INFO__ - LOG.debug("pyMoul version: %s" % moul_version) - LOG.debug("Python: %s" % repr(sys.version_info)) - LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) - LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) - LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" - % platform.uname()) - LOG.debug("platform name: %s" % platform.platform(True)) - LOG.debug("sys.frozen status: %s" % __FROZEN__) - LOG.debug("OS detected: win32: %r, cygwin: %r, Linux: %r, Mac: %r, BSD: %r, " + LOG.info("pyMoul version: %s" % moul_version) + LOG.info("Python: %s" % repr(sys.version_info)) + LOG.info("Python: %s" % sys.version.replace('\n', ' ')) + LOG.info("Platform: %s, OS name: %s" % (sys.platform, os.name)) + LOG.info("system %r, node %r, release %r, version %r, machine %r, processor %r" + % platform.uname()) + LOG.info("platform name: %s" % platform.platform(True)) + LOG.info("sys.frozen status: %s" % __FROZEN__) + LOG.info("OS detected: win32: %r, cygwin: %r, Linux: %r, Mac: %r, BSD: %r, " "posix/Un*x: %r, NT: %r" % __INFO__) # no setup the logging stuff! Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-28 17:15:47 UTC (rev 93) @@ -142,7 +142,8 @@ raise ValueError("Datadir's parent dir does not exist: %s" % par) else: - LOG.debug("Creating pyMoul data dir %s" % datadir) + LOG.info("Creating pyMoul data dir %s" % datadir) os.mkdir(datadir, 0750) - LOG.debug("Using pyMoul data dir %s" % datadir) + LOG.info("Using pyMoul data dir %s" % datadir) return datadir + Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-28 17:15:47 UTC (rev 93) @@ -520,11 +520,11 @@ self.text_ping.insertPlainText("PING: %0.3f\n" % time) def on_pingthread_dnserror(self, name, errcode, errmsg): - LOG.debug('dns error: %s, %i, %s' % (name, errcode, errmsg)) + LOG.error('dns error: %s, %i, %s' % (name, errcode, errmsg)) self.text_ping.insertPlainText("%s ... DNS error: %s\n" % (name, errmsg)) def on_pingthread_pingerror(self, name, errcode, errmsg): - LOG.debug('ping error: %s, %i, %s' % (name, errcode, errmsg)) + LOG.error('ping error: %s, %i, %s' % (name, errcode, errmsg)) self.text_ping.insertPlainText("PING error: %s\n" % errmsg) @pyqtSignature("bool") Modified: pymoul/trunk/src/moul/qt/ui/moulqt_rc.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/moulqt_rc.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/qt/ui/moulqt_rc.py 2007-01-28 17:15:47 UTC (rev 93) @@ -2,8 +2,8 @@ # Resource object code # -# Created: Mi 17. Jan 17:01:45 2007 -# by: The Resource Compiler for PyQt (Qt v4.2.2) +# Created: So Jan 28 18:10:39 2007 +# by: The Resource Compiler for PyQt (Qt v4.2.0) # # WARNING! All changes made in this file will be lost! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-28 16:43:17
|
Revision: 92 http://pymoul.svn.sourceforge.net/pymoul/?rev=92&view=rev Author: tiran Date: 2007-01-28 08:43:16 -0800 (Sun, 28 Jan 2007) Log Message: ----------- Added translation files Modified Paths: -------------- pymoul/trunk/Makefile.in pymoul/trunk/src/moul/osdependent/singleapp.py pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts Added Paths: ----------- pymoul/trunk/src/moul/qt/i18n/pymoul_de.qm pymoul/trunk/src/moul/qt/i18n/pymoul_es.qm pymoul/trunk/src/moul/qt/i18n/pymoul_es.ts pymoul/trunk/src/moul/qt/i18n/pymoul_fr.qm pymoul/trunk/src/moul/qt/i18n/pymoul_fr.ts pymoul/trunk/src/moul/qt/i18n/pymoul_it.qm pymoul/trunk/src/moul/qt/i18n/pymoul_it.ts Property Changed: ---------------- pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts Modified: pymoul/trunk/Makefile.in =================================================================== --- pymoul/trunk/Makefile.in 2007-01-28 15:49:22 UTC (rev 91) +++ pymoul/trunk/Makefile.in 2007-01-28 16:43:16 UTC (rev 92) @@ -1,5 +1,11 @@ PYTHON?=python EPYDOC=$(PYTHON) -c "import epydoc.cli; epydoc.cli.cli()" +NOTSVN=-a -not -wholename '*.svn*' +FINDPYTXT=find src/moul \( -name '*.py' -o -name '*.txt' \) $(NOTSVN) +FINDPY=find src/moul -name '*.py' $(NOTSVN) +FINDQT=find src/moul/qt \( -name '*.py' -o -name '*.ui' \) $(NOTSVN) +FINDTEXT=find src/moul \( -name '*.py' -o -name '*.txt' -o -name '*.qrc' -o -name '*.ui' -o -name '*.ts' \) $(NOTSVN) +LANGS=de fr it es TESTFLAGS=-v TESTOPTS= SETUPFLAGS= @@ -60,8 +66,15 @@ $(PYTHON) setup.py clean -a propset: - find src/moul \( -name '*.py' -o -name '*.txt' \) -a -not -wholename '*.svn*' | xargs svn propset svn:keywords "Id Revision" - find src/moul \( -name '*.py' -o -name '*.txt' -o -name '*.qrc' -o -name '*.ui' \) -a -not -wholename '*.svn*' | xargs svn propset svn:eol-style "native" - find . -maxdepth 1 \( -name '*.py' -o -name '*.txt' \) | xargs svn propset svn:keywords "Id Revisioni" - find . -maxdepth 1 \( -name '*.py' -o -name '*.txt' \) | xargs svn propset svn:eol-style "native" + $(FINDPYTXT) | xargs svn propset svn:keywords "Id Revision" + $(FINDTEXT) | xargs svn propset svn:eol-style "native" +fixlineendings: + $(FINDPY) | xargs recode -f ibmpc..latin1 + +updatelangs: + for L in $(LANGS); do \ + pylupdate4 `$(FINDQT)` -ts src/moul/qt/i18n/pymoul_$${L}.ts;\ + lrelease src/moul/qt/i18n/pymoul_$${L}.ts; \ + done + Modified: pymoul/trunk/src/moul/osdependent/singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-28 15:49:22 UTC (rev 91) +++ pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-28 16:43:16 UTC (rev 92) @@ -33,8 +33,8 @@ True >>> os.path.isfile(lckfile) True ->>> singleapp.checkLocked() is None -True +>>> singleapp.checkLocked() +2 >>> singleapp.release() >>> os.path.isfile(lckfile) False @@ -151,10 +151,10 @@ self._locked = False def checkLocked(self): - """Check if another process has a lock + """Check a process has a lock """ if self._locked: - return True + return 2 try: lock(self._fd, LOCK) except (IOError, OSError): Added: pymoul/trunk/src/moul/qt/i18n/pymoul_de.qm =================================================================== (Binary files differ) Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_de.qm ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Modified: pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts =================================================================== --- pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts 2007-01-28 15:49:22 UTC (rev 91) +++ pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts 2007-01-28 16:43:16 UTC (rev 92) @@ -2,34 +2,6 @@ <context> <name>MainWindow</name> <message> - <source>MOUL is running</source> - <translation type="unfinished"></translation> - </message> - <message> - <source>MOUL</source> - <translation type="unfinished"></translation> - </message> - <message> - <source>MOUL is not running</source> - <translation type="unfinished"></translation> - </message> - <message> - <source>Not Implemented</source> - <translation type="unfinished"></translation> - </message> - <message> - <source>Sorry, this feature is not implemented yet!</source> - <translation type="unfinished"></translation> - </message> - <message> - <source>Error opening graphics.ini</source> - <translation type="unfinished"></translation> - </message> - <message> - <source>Error opening audio.ini</source> - <translation type="unfinished"></translation> - </message> - <message> <source>Tool for Myst Online</source> <translation type="unfinished"></translation> </message> @@ -244,5 +216,33 @@ <source>About</source> <translation type="unfinished"></translation> </message> + <message> + <source>MOUL is running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is not running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Not Implemented</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sorry, this feature is not implemented yet!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening graphics.ini</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening audio.ini</source> + <translation type="unfinished"></translation> + </message> </context> </TS> Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts ___________________________________________________________________ Name: svn:eol-style + native Added: pymoul/trunk/src/moul/qt/i18n/pymoul_es.qm =================================================================== (Binary files differ) Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_es.qm ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: pymoul/trunk/src/moul/qt/i18n/pymoul_es.ts =================================================================== --- pymoul/trunk/src/moul/qt/i18n/pymoul_es.ts (rev 0) +++ pymoul/trunk/src/moul/qt/i18n/pymoul_es.ts 2007-01-28 16:43:16 UTC (rev 92) @@ -0,0 +1,248 @@ +<!DOCTYPE TS><TS> +<context> + <name>MainWindow</name> + <message> + <source>Tool for Myst Online</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Configure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Windowed</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Vertical Sync</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Display Shadows</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Screen Resolution</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>800x600 (4:3)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Texture Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Low</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>High</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anti-Aliasing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Med.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ultra</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Shadow Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anisotropic-Filtering</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPC Voices</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound FX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ambience Sound</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Mute all</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hardware</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio Modes</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Generic Software</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable EAX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Voice chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Microphon Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable Voice Chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time zones</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cavern time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cyan time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>UTC -0</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Mountain Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Pacific Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>D'ni time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping</source> + <translation type="unfinished"></translation> + </message> + <message> + <source><html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal; text-decoration:none;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Browse in game documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Age</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Element</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Set</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>pyMoul tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>About</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is not running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Not Implemented</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sorry, this feature is not implemented yet!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening graphics.ini</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening audio.ini</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_es.ts ___________________________________________________________________ Name: svn:eol-style + native Added: pymoul/trunk/src/moul/qt/i18n/pymoul_fr.qm =================================================================== (Binary files differ) Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_fr.qm ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: pymoul/trunk/src/moul/qt/i18n/pymoul_fr.ts =================================================================== --- pymoul/trunk/src/moul/qt/i18n/pymoul_fr.ts (rev 0) +++ pymoul/trunk/src/moul/qt/i18n/pymoul_fr.ts 2007-01-28 16:43:16 UTC (rev 92) @@ -0,0 +1,248 @@ +<!DOCTYPE TS><TS> +<context> + <name>MainWindow</name> + <message> + <source>Tool for Myst Online</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Configure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Windowed</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Vertical Sync</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Display Shadows</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Screen Resolution</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>800x600 (4:3)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Texture Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Low</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>High</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anti-Aliasing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Med.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ultra</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Shadow Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anisotropic-Filtering</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPC Voices</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound FX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ambience Sound</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Mute all</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hardware</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio Modes</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Generic Software</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable EAX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Voice chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Microphon Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable Voice Chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time zones</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cavern time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cyan time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>UTC -0</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Mountain Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Pacific Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>D'ni time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping</source> + <translation type="unfinished"></translation> + </message> + <message> + <source><html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal; text-decoration:none;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Browse in game documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Age</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Element</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Set</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>pyMoul tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>About</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is not running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Not Implemented</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sorry, this feature is not implemented yet!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening graphics.ini</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening audio.ini</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_fr.ts ___________________________________________________________________ Name: svn:eol-style + native Added: pymoul/trunk/src/moul/qt/i18n/pymoul_it.qm =================================================================== (Binary files differ) Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_it.qm ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: pymoul/trunk/src/moul/qt/i18n/pymoul_it.ts =================================================================== --- pymoul/trunk/src/moul/qt/i18n/pymoul_it.ts (rev 0) +++ pymoul/trunk/src/moul/qt/i18n/pymoul_it.ts 2007-01-28 16:43:16 UTC (rev 92) @@ -0,0 +1,248 @@ +<!DOCTYPE TS><TS> +<context> + <name>MainWindow</name> + <message> + <source>Tool for Myst Online</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Configure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Windowed</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Vertical Sync</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Display Shadows</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Screen Resolution</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>800x600 (4:3)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Texture Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Low</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>High</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anti-Aliasing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Med.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ultra</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Shadow Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anisotropic-Filtering</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPC Voices</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound FX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ambience Sound</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Mute all</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hardware</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio Modes</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Generic Software</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable EAX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Voice chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Microphon Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable Voice Chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time zones</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cavern time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cyan time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>UTC -0</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Mountain Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Pacific Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>D'ni time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping</source> + <translation type="unfinished"></translation> + </message> + <message> + <source><html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal; text-decoration:none;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Browse in game documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Age</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Element</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Set</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>pyMoul tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>About</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is not running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Not Implemented</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sorry, this feature is not implemented yet!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening graphics.ini</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening audio.ini</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> Property changes on: pymoul/trunk/src/moul/qt/i18n/pymoul_it.ts ___________________________________________________________________ Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-28 15:49:23
|
Revision: 91 http://pymoul.svn.sourceforge.net/pymoul/?rev=91&view=rev Author: tiran Date: 2007-01-28 07:49:22 -0800 (Sun, 28 Jan 2007) Log Message: ----------- Added pymoul translation file Changed doc strings - pylupdate4's parser doesn't understand some constructs with triple quotes Modified Paths: -------------- pymoul/trunk/src/moul/qt/localization.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/moulqt.py pymoul/trunk/src/moul/qt/ui/__init__.py Added Paths: ----------- pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts Added: pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts =================================================================== --- pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts (rev 0) +++ pymoul/trunk/src/moul/qt/i18n/pymoul_de.ts 2007-01-28 15:49:22 UTC (rev 91) @@ -0,0 +1,248 @@ +<!DOCTYPE TS><TS> +<context> + <name>MainWindow</name> + <message> + <source>MOUL is running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MOUL is not running</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Not Implemented</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sorry, this feature is not implemented yet!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening graphics.ini</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error opening audio.ini</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Tool for Myst Online</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Configure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Windowed</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Vertical Sync</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Display Shadows</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Screen Resolution</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>800x600 (4:3)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Texture Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Low</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>High</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anti-Aliasing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Med.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ultra</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Shadow Quality</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Anisotropic-Filtering</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Graphics</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPC Voices</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound FX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ambience Sound</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Mute all</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hardware</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio Modes</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Generic Software</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable EAX</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Voice chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Microphon Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enable Voice Chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time zones</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cavern time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cyan time:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>UTC -0</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Mountain Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>(Pacific Standard Time)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>D'ni time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ping</source> + <translation type="unfinished"></translation> + </message> + <message> + <source><html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal; text-decoration:none;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Servers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Browse in game documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Age</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Element</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Set</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Documents</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>pyMoul tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>About</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> Modified: pymoul/trunk/src/moul/qt/localization.py =================================================================== --- pymoul/trunk/src/moul/qt/localization.py 2007-01-28 15:23:44 UTC (rev 90) +++ pymoul/trunk/src/moul/qt/localization.py 2007-01-28 15:49:22 UTC (rev 91) @@ -15,6 +15,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # Temple Place, Suite 330, Boston, MA 02111-1307 USA # + """Moul localization / documents """ __author__ = "Christian Heimes" @@ -43,8 +44,9 @@ return QtCore.QStringList(dummy+lst) class LocalizationMixin(object): - """Mixin for documents tab """ + Mixin for documentation tab + """ def _documents_init(self): locDir = lookupDir('loc') if not os.path.isdir(locDir): Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-28 15:23:44 UTC (rev 90) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-28 15:49:22 UTC (rev 91) @@ -15,6 +15,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # Temple Place, Suite 330, Boston, MA 02111-1307 USA # + """Moul QT GUI main windows """ from __future__ import with_statement @@ -47,8 +48,9 @@ LOG = getLogger('moul.qt') def criticalMessageBox(self, title, text): - """Critical warning! """ + Critical warning! + """ mb = QtGui.QMessageBox() mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) mb.setIcon(QtGui.QMessageBox.Critical) @@ -110,14 +112,16 @@ QtGui.QSystemTrayIcon.Information, 10000) def _notimplemented(self): - """TODO: remove me """ + TODO: remove me + """ QtGui.QMessageBox.information(self, self.trUtf8("Not Implemented"), self.trUtf8("""Sorry, this feature is not implemented yet!""")) def closeEvent(self, event): - """Close event handler + """ + Close event handler @param event close event (QCloseEvent) """ @@ -129,7 +133,8 @@ event.accept() def keyPressEvent(self, event): - """Key event handler + """ + Key event handler @param event key event (QKeyEvent) @@ -141,8 +146,9 @@ event.ignore() def setDirty(self, boolean): - """Sets the save state """ + Sets the save state + """ self._dirty = bool(boolean) #self.main_buttonbox_reset.setEnabled(boolean) #self.main_buttonbox_save.setEnabled(boolean) @@ -164,8 +170,9 @@ # graphics settings def _graphics_init(self): - """init graphics tab """ + init graphics tab + """ self.connect(self, SIGNAL("graphicsini_loaded()"), self.on_graphicsini_loaded) self.connect(self, SIGNAL("graphicsini_reset()"), self.on_graphicsini_reset) self.connect(self, SIGNAL("graphicsini_save()"), self.on_graphicsini_save) @@ -175,8 +182,9 @@ @signalLogDecorator(LOG) def on_graphicsini_loaded(self): - """SIGNAL graphicsini_loaded() """ + SIGNAL graphicsini_loaded() + """ inipath = lookupDir('ini') self._graphics_ini = gini = GraphicsIni() try: @@ -191,22 +199,25 @@ @signalLogDecorator(LOG) def on_graphicsini_reset(self): - """SIGNAL graphicsini_reset() """ + SIGNAL graphicsini_reset() + """ self._graphics_ini.reset() self._graphicsini_setstate() @signalLogDecorator(LOG) def on_graphicsini_save(self): - """SIGNAL graphicsini_save() """ + SIGNAL graphicsini_save() + """ #self._notimplemented() self._graphics_ini.write() self.setDirty(False) def _graphicsini_setstate(self): - """Set sliders according to graphics ini settings """ + Set sliders according to graphics ini settings + """ gini = self._graphics_ini length = len(videoModes) - 1 self.sl_gra_screenres.setMaximum(length) @@ -224,8 +235,9 @@ @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_screenres_valueChanged(self, idx): - """SIGNAL: valueChanged (int) """ + SIGNAL: valueChanged (int) + """ # XXX: fixme txt = videoModes.getVidModeHuman(idx) self.lb_screenres.setText(QtCore.QString(txt)) @@ -234,73 +246,83 @@ @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_screenres_sliderMoved(self, idx): - """SIGNAL: sliderMoved(int) """ + SIGNAL: sliderMoved(int) + """ txt = videoModes.getVidModeHuman(idx) self.lb_screenres.setText(QtCore.QString(txt)) @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_quality_valueChanged(self, idx): - """SIGNAL: valueChanged (int) """ + SIGNAL: valueChanged (int) + """ self._graphics_ini.quality = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_texture_valueChanged(self, idx): - """SIGNAL: valueChanged (int) """ + SIGNAL: valueChanged (int) + """ self._graphics_ini.texture = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_antialias_valueChanged(self, idx): - """SIGNAL: valueChanged (int) """ + SIGNAL: valueChanged (int) + """ self._graphics_ini.antialias = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_anisotropic_valueChanged(self, idx): - """SIGNAL: valueChanged (int) """ + SIGNAL: valueChanged (int) + """ self._graphics_ini.anisotropic = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_shadow_valueChanged(self, idx): - """SIGNAL: valueChanged (int) """ + SIGNAL: valueChanged (int) + """ self._graphics_ini.shadow = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_gra_windowed_stateChanged(self, state): - """SIGNAL: stateChanged(int) """ + SIGNAL: stateChanged(int) + """ self._graphics_ini.windowed = state @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_gra_vsync_stateChanged (self, state): - """SIGNAL: stateChanged(int) """ + SIGNAL: stateChanged(int) + """ self._graphics_ini.vsync = state @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_gra_shadow_stateChanged (self, state): - """SIGNAL: stateChanged(int) """ + SIGNAL: stateChanged(int) + """ self._graphics_ini.shadow_enabled = state # ************************************************************************ # audio settings def _audio_init(self): - """init graphics tab """ + init graphics tab + """ self.connect(self, SIGNAL("audioini_loaded()"), self.on_audioini_loaded) self.connect(self, SIGNAL("audiini_reset()"), self.on_audioini_reset) self.connect(self, SIGNAL("audiini_save()"), self.on_audioini_save) @@ -310,8 +332,9 @@ @signalLogDecorator(LOG) def on_audioini_loaded(self): - """SIGNAL: audioini_loaded() """ + SIGNAL: audioini_loaded() + """ inipath = lookupDir('ini') self._audio_ini = aini = AudioIni() try: @@ -326,22 +349,25 @@ @signalLogDecorator(LOG) def on_audioini_reset(self): - """SIGNAL audioini_reset() """ + SIGNAL audioini_reset() + """ self._audio_ini.reset() self._audioini_setstate() @signalLogDecorator(LOG) def on_audioini_save(self): - """SIGNAL audioini_save() """ + SIGNAL audioini_save() + """ #self._notimplemented() self._audio_ini.write() self.setDirty(False) # urks def _audioini_setstate(self): - """Set sliders according to audio ini settings """ + Set sliders according to audio ini settings + """ aini = self._audio_ini self.sl_aud_device.setMaximum(aini.numberOfDevices()-1) @@ -358,8 +384,6 @@ @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_device_valueChanged(self, idx): - """SIGNAL: valueChanged (int) - """ self._audio_ini.device = idx txt = self._audio_ini.getDeviceName(idx) self.lb_aud_device.setText(QtCore.QString(txt[1:-1])) @@ -367,72 +391,55 @@ @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_device_sliderMoved(self, idx): - """SIGNAL: sliderMoved(int) - """ txt = self._audio_ini.getDeviceName(idx) self.lb_aud_device.setText(QtCore.QString(txt[1:-1])) @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_npc_valueChanged(self, idx): - """SIGNAL: valueChanged (int) - """ self._audio_ini.npc = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_music_valueChanged(self, idx): - """SIGNAL: valueChanged (int) - """ self._audio_ini.music = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_fx_valueChanged(self, idx): - """SIGNAL: valueChanged (int) - """ self._audio_ini.fx = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_ambience_valueChanged(self, idx): - """SIGNAL: valueChanged (int) - """ self._audio_ini.ambience = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_priority_valueChanged(self, idx): - """SIGNAL: valueChanged (int) - """ self._audio_ini.priority = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_aud_eax_stateChanged (self, state): - """SIGNAL: stateChanged(int) - """ self._audio_ini.eax = state @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_aud_mute_stateChanged (self, state): - """SIGNAL: stateChanged(int) - """ self._audio_ini.mute = state @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_aud_voicechat_stateChanged (self, state): - """SIGNAL: stateChanged(int) - """ self._audio_ini.voicechat = state # ************************************************************************ # time zones def _timezone_init(self): - """Init time zone tab""" + """ + Init time zone tab""" # create info object and update display the first time self._caverntime = CavernTime() self._timezone_update() @@ -445,7 +452,9 @@ timer.start() def _timezone_update(self): - """Update datetime widgets""" + """ + Update datetime widgets + """ ct = self._caverntime.info() self.dt_cavern.setDateTime(ct['cavern']['datetime']) @@ -461,8 +470,9 @@ @pyqtSignature("") def on_timezone_timer_timeout(self): - """SIGNAL: QTimer timeout """ + SIGNAL: QTimer timeout + """ ct = self._caverntime() self.dt_cavern.setDateTime(ct['cavern']) self.dt_pacific.setDateTime(ct['pacific']) @@ -470,8 +480,9 @@ # ************************************************************************ # ping def _ping_init(self): - """init ping tab """ + init ping tab + """ self._ping_thread = thread = PingServerThread() self.connect(thread, SIGNAL("started"), @@ -597,3 +608,4 @@ self.mutex.unlock() if not self._running: return + Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-28 15:23:44 UTC (rev 90) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-28 15:49:22 UTC (rev 91) @@ -16,6 +16,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # Temple Place, Suite 330, Boston, MA 02111-1307 USA # + """Moul QT GUI main module """ __author__ = "Christian Heimes" Modified: pymoul/trunk/src/moul/qt/ui/__init__.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/__init__.py 2007-01-28 15:23:44 UTC (rev 90) +++ pymoul/trunk/src/moul/qt/ui/__init__.py 2007-01-28 15:49:22 UTC (rev 91) @@ -15,6 +15,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # Temple Place, Suite 330, Boston, MA 02111-1307 USA # + """ """ __author__ = "Christian Heimes" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-28 15:23:45
|
Revision: 90 http://pymoul.svn.sourceforge.net/pymoul/?rev=90&view=rev Author: tiran Date: 2007-01-28 07:23:44 -0800 (Sun, 28 Jan 2007) Log Message: ----------- Changed import behavior and fixed smaller issues in singleapp Modified Paths: -------------- pymoul/trunk/INSTALL.txt pymoul/trunk/setup_win32.py pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/osdependent/linux/__init__.py pymoul/trunk/src/moul/osdependent/singleapp.py pymoul/trunk/src/moul/qt/__init__.py pymoul/trunk/src/moul/qt/ui/mainwindow.py Added Paths: ----------- pymoul/trunk/src/moul/qt/i18n/ Property Changed: ---------------- pymoul/trunk/ Property changes on: pymoul/trunk ___________________________________________________________________ Name: svn:ignore - build dist *.e4? + build dist *.e4? Makefile Modified: pymoul/trunk/INSTALL.txt =================================================================== --- pymoul/trunk/INSTALL.txt 2007-01-27 22:29:40 UTC (rev 89) +++ pymoul/trunk/INSTALL.txt 2007-01-28 15:23:44 UTC (rev 90) @@ -5,7 +5,7 @@ * Python 2.5.x http://www.python.org/ * easy_install http://peak.telecommunity.com/DevCenter/EasyInstall * setuptools (via easy install) - * PyTz (via $ easy_install pytz) + * PyTz (via $ easy_install-2.5 pytz) * Qt4 GPL 4.2+ http://www.trolltech.com/developer/downloads/qt/ * PyQt4 4.1.1+ http://www.riverbankcomputing.co.uk/pyqt/ @@ -13,7 +13,7 @@ ------- * pywin32 http://sourceforge.net/projects/pywin32/ - * py2exe http://www.py2exe.org/ + * py2exe http://www.py2exe.org/ (via $ easy_install-2.5 py2exe) * MinGW32 compiler (bundled with Qt4) Tools @@ -21,6 +21,7 @@ * UPX http://upx.sourceforge.net/#download * InnoSetup http://www.jrsoftware.org/ + * epydoc 3.0+ (via $ easy_install-2.5 epydoc) ==================== Windows Installation Modified: pymoul/trunk/setup_win32.py =================================================================== --- pymoul/trunk/setup_win32.py 2007-01-27 22:29:40 UTC (rev 89) +++ pymoul/trunk/setup_win32.py 2007-01-28 15:23:44 UTC (rev 90) @@ -68,8 +68,7 @@ pexe = kw['options'].setdefault('py2exe', {}) pexe['compressed'] = 100 # compress zip file pexe['optimize'] = 0 # 0,1,2 - pexe['includes'] = ['sip', 'PyQt4', 'encodings', 'encodings.*', - 'moul.osdependent.win32', 'moul.osdependent.win32.*'] + pexe['includes'] = ['sip', 'PyQt4', 'encodings', 'encodings.*'] # SSL currently not in use but imported by socket pexe['excludes'] = ['_ssl', 'win32pipe', 'win32evtlog', 'win32file', 'win32api'] # added by logging.handlers.SMTPHandler but not yet required Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-27 22:29:40 UTC (rev 89) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-28 15:23:44 UTC (rev 90) @@ -35,6 +35,8 @@ import os import sys +from types import ModuleType + from moul.log import getLogger from moul.osdependent.processinfo import getPids from moul.osdependent.processinfo import getPidNames @@ -65,7 +67,10 @@ def _importHelper(modname, names=None, target=None): """Import a list of variables from a module - + + >>> mod = _importHelper(sys) + >>> mod is sys or mod + True >>> mod = _importHelper('moul.osdependent') >>> mod == _thismodule or mod True @@ -88,7 +93,11 @@ >>> vars[0] is _marker True """ - mod = __import__(modname, globals(), locals(), ['']) + if not isinstance(modname, ModuleType): + mod = __import__(modname, globals(), locals(), ['']) + else: + mod = modname + if names is None: return mod else: @@ -107,11 +116,14 @@ # XXX: what about cygwin, bsd and others? _thismodule = sys.modules[__name__] if __WIN32__: - _importHelper('moul.osdependent.win32', NAMES, target=_thismodule) + from moul.osdependent import win32 as osdep_win32 + _importHelper(osdep_win32, NAMES, target=_thismodule) elif __LINUX__: - _importHelper('moul.osdependent.linux', NAMES, target=_thismodule) + from moul.osdependent import linux as osdep_linux + _importHelper(osdep_linux, NAMES, target=_thismodule) elif __MACOSX__: - _importHelper('moul.osdependent.darwin', NAMES, target=_thismodule) + from moul.osdependent import darwin as osdep_darwin + _importHelper(osdep_darwin, NAMES, target=_thismodule) else: raise RuntimeError('platform %s not supported' % sys.platform) Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-27 22:29:40 UTC (rev 89) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-28 15:23:44 UTC (rev 90) @@ -28,7 +28,7 @@ LOG = getLogger('moul.linux') LOG.critical('Linux support is not tested') -MOUL_DIR = "Uru Live" +MOUL_DIR = ".urulive" INI_FILE = ('pyMoul', 'pymoul.ini') EXEC_NAME = "UruLauncher" HOME = os.environ['HOME'] Modified: pymoul/trunk/src/moul/osdependent/singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-27 22:29:40 UTC (rev 89) +++ pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-28 15:23:44 UTC (rev 90) @@ -106,6 +106,7 @@ self.pid = pid self.ext = ext self._fd = None + self._locked = False self.lckfile = self._genFilename() # register atexit function atexit.register(self.release) @@ -123,10 +124,12 @@ if self._fd is not None: self._fd.close() self._fd = None + self._locked = False raise SingleAppError("Another instance is already running") else: self._fd.write(str(self.pid)) self._fd.flush() + self._locked = True LOG.info("Create lock file %s for PID %i" % (self.lckfile, self.pid)) return self.lckfile, self.pid @@ -145,18 +148,18 @@ if os.path.isfile(self.lckfile): LOG.info("Remove lock file %s" % self.lckfile) os.unlink(self.lckfile) - + self._locked = False + def checkLocked(self): """Check if another process has a lock """ + if self._locked: + return True try: - fd = open(self.lckfile, 'a+') - fd.close() - except OSError: + lock(self._fd, LOCK) + except (IOError, OSError): return True else: - if self._fd: - return None return False def _genFilename(self): Modified: pymoul/trunk/src/moul/qt/__init__.py =================================================================== --- pymoul/trunk/src/moul/qt/__init__.py 2007-01-27 22:29:40 UTC (rev 89) +++ pymoul/trunk/src/moul/qt/__init__.py 2007-01-28 15:23:44 UTC (rev 90) @@ -15,8 +15,11 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # Temple Place, Suite 330, Boston, MA 02111-1307 USA # + """ +moul.qt package with Qt4 UI """ + __author__ = "Christian Heimes" __version__ = "$Id$" __revision__ = "$Revision$" Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-27 22:29:40 UTC (rev 89) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-28 15:23:44 UTC (rev 90) @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'src\moul\qt\ui\mainwindow.ui' +# Form implementation generated from reading ui file 'src/moul/qt/ui/mainwindow.ui' # -# Created: Fri Jan 26 19:48:46 2007 +# Created: Sun Jan 28 15:25:00 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-27 22:29:40
|
Revision: 89 http://pymoul.svn.sourceforge.net/pymoul/?rev=89&view=rev Author: tiran Date: 2007-01-27 14:29:40 -0800 (Sat, 27 Jan 2007) Log Message: ----------- Propset eol-style and keywords Renamed Makefile to Makefile.in Tests and better implementation for locking and singleapp Modified Paths: -------------- pymoul/trunk/compileui.py pymoul/trunk/setup.py pymoul/trunk/setup_win32.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/processinfo.py pymoul/trunk/src/moul/osdependent/singleapp.py pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py pymoul/trunk/src/moul/osdependent/win32/__init__.py pymoul/trunk/src/moul/qt/moulqt.py Added Paths: ----------- pymoul/trunk/Makefile.in pymoul/trunk/src/moul/osdependent/tests/test_processinfo.py Removed Paths: ------------- pymoul/trunk/Makefile Property Changed: ---------------- pymoul/trunk/AUTHORS.txt pymoul/trunk/GPL.txt pymoul/trunk/INSTALL.txt pymoul/trunk/README.txt pymoul/trunk/compileui.py pymoul/trunk/distutils_upx.py pymoul/trunk/ez_setup.py pymoul/trunk/setup.py pymoul/trunk/setup_win32.py pymoul/trunk/src/moul/config/tests/test_config.py pymoul/trunk/src/moul/file/tests/audio.txt pymoul/trunk/src/moul/file/tests/audiocaps.0.txt pymoul/trunk/src/moul/file/tests/graphics.txt pymoul/trunk/src/moul/file/tests/test_chatlog.py pymoul/trunk/src/moul/file/tests/test_kiimage.py pymoul/trunk/src/moul/file/tests/test_localization.py pymoul/trunk/src/moul/file/tests/test_plasmalog.py pymoul/trunk/src/moul/file/tests/test_wdysini.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/processinfo.py pymoul/trunk/src/moul/osdependent/singleapp.py pymoul/trunk/src/moul/osdependent/tests/__init__.py pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py pymoul/trunk/src/moul/osdependent/win32/__init__.py pymoul/trunk/src/moul/osdependent/win32/registry.py pymoul/trunk/src/moul/osdependent/win32/winpath.py pymoul/trunk/src/moul/qt/localization.py pymoul/trunk/src/moul/qt/ui/README.txt pymoul/trunk/src/moul/server/__init__.py pymoul/trunk/src/moul/server/ping.py pymoul/trunk/src/moul/server/serverlist.py pymoul/trunk/src/moul/server/tests/__init__.py pymoul/trunk/src/moul/server/tests/test_ping.py pymoul/trunk/src/moul/server/tests/test_serverlist.py pymoul/trunk/src/moul/time/README.txt pymoul/trunk/src/moul/time/tests/test_dni.py pymoul/trunk/test.py pymoul/trunk/version.txt Property changes on: pymoul/trunk/AUTHORS.txt ___________________________________________________________________ Name: svn:keywords + Id Revisioni Property changes on: pymoul/trunk/GPL.txt ___________________________________________________________________ Name: svn:keywords + Id Revisioni Property changes on: pymoul/trunk/INSTALL.txt ___________________________________________________________________ Name: svn:keywords + Id Revisioni Deleted: pymoul/trunk/Makefile =================================================================== --- pymoul/trunk/Makefile 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/Makefile 2007-01-27 22:29:40 UTC (rev 89) @@ -1,61 +0,0 @@ -PYTHON?=python -EPYDOC=$(PYTHON) -c "import epydoc.cli; epydoc.cli.cli()" -TESTFLAGS=-v -TESTOPTS= -SETUPFLAGS= - -all: inplace - -# Build in-place -inplace: - PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) build_ext -i - -build: compileui - PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) build - -py2exe: - PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) py2exe - -innosetup: - PYTHONPATH="src" INNOSETUP="yes" $(PYTHON) setup.py $(SETUPFLAGS) py2exe - -bdist_egg: - PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) bdist_egg - -run: compileui - PYTHONPATH="src" $(PYTHON) src/moul/qt/moulqt.py - -exerun: compileui py2exe - dist/moulqt.exe - -compileui: - $(PYTHON) compileui.py - -test_build: build compileui - PYTHONPATH="src" $(PYTHON) test.py $(TESTFLAGS) $(TESTOPTS) - -test_inplace: compileui - PYTHONPATH="src" $(PYTHON) test.py $(TESTFLAGS) $(TESTOPTS) - -doc_html: - PYTHONPATH="src" $(EPYDOC) -v --html --output="doc/html" moul - -# What should the default be? -test: test_inplace - -exe: py2exe - -installer: innosetup - -egg: bdist_egg - -doc: doc_html - -clean: - find . \( -name '*.o' -o -name '*.c' -o -name '*.so' -o -name '*.py[cod]' -o -name '*.dll' \) -exec rm -f {} \; - rm -rf build - -realclean: clean - rm -f TAGS - $(PYTHON) setup.py clean -a - Copied: pymoul/trunk/Makefile.in (from rev 88, pymoul/trunk/Makefile) =================================================================== --- pymoul/trunk/Makefile.in (rev 0) +++ pymoul/trunk/Makefile.in 2007-01-27 22:29:40 UTC (rev 89) @@ -0,0 +1,67 @@ +PYTHON?=python +EPYDOC=$(PYTHON) -c "import epydoc.cli; epydoc.cli.cli()" +TESTFLAGS=-v +TESTOPTS= +SETUPFLAGS= + +all: inplace + +# Build in-place +inplace: + PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) build_ext -i + +build: compileui + PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) build + +py2exe: + PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) py2exe + +innosetup: + PYTHONPATH="src" INNOSETUP="yes" $(PYTHON) setup.py $(SETUPFLAGS) py2exe + +bdist_egg: + PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) bdist_egg + +run: compileui + PYTHONPATH="src" $(PYTHON) src/moul/qt/moulqt.py + +exerun: compileui py2exe + dist/moulqt.exe + +compileui: + $(PYTHON) compileui.py + +test_build: build compileui + PYTHONPATH="src" $(PYTHON) test.py $(TESTFLAGS) $(TESTOPTS) + +test_inplace: compileui + PYTHONPATH="src" $(PYTHON) test.py $(TESTFLAGS) $(TESTOPTS) + +doc_html: + PYTHONPATH="src" $(EPYDOC) -v --html --output="doc/html" moul + +# What should the default be? +test: test_inplace + +exe: py2exe + +installer: innosetup + +egg: bdist_egg + +doc: doc_html + +clean: + find . \( -name '*.o' -o -name '*.c' -o -name '*.so' -o -name '*.py[cod]' -o -name '*.dll' \) -exec rm -f {} \; + rm -rf build + +realclean: clean + rm -f TAGS + $(PYTHON) setup.py clean -a + +propset: + find src/moul \( -name '*.py' -o -name '*.txt' \) -a -not -wholename '*.svn*' | xargs svn propset svn:keywords "Id Revision" + find src/moul \( -name '*.py' -o -name '*.txt' -o -name '*.qrc' -o -name '*.ui' \) -a -not -wholename '*.svn*' | xargs svn propset svn:eol-style "native" + find . -maxdepth 1 \( -name '*.py' -o -name '*.txt' \) | xargs svn propset svn:keywords "Id Revisioni" + find . -maxdepth 1 \( -name '*.py' -o -name '*.txt' \) | xargs svn propset svn:eol-style "native" + Property changes on: pymoul/trunk/README.txt ___________________________________________________________________ Name: svn:keywords + Id Revisioni Modified: pymoul/trunk/compileui.py =================================================================== --- pymoul/trunk/compileui.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/compileui.py 2007-01-27 22:29:40 UTC (rev 89) @@ -3,7 +3,7 @@ """ __author__ = "Christian Heimes" __version__ = "$Id$" -__revision__ = "$Revision$" +__revision__ = "$Revision: 45 $" import os import re Property changes on: pymoul/trunk/compileui.py ___________________________________________________________________ Name: svn:keywords - Id Revision + Id Revisioni Property changes on: pymoul/trunk/distutils_upx.py ___________________________________________________________________ Name: svn:keywords + Id Revisioni Property changes on: pymoul/trunk/ez_setup.py ___________________________________________________________________ Name: svn:keywords - Id Revision + Id Revisioni Modified: pymoul/trunk/setup.py =================================================================== --- pymoul/trunk/setup.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/setup.py 2007-01-27 22:29:40 UTC (rev 89) @@ -5,7 +5,7 @@ """ __author__ = "Christian Heimes" __version__ = "$Id$" -__revision__ = "$Revision$" +__revision__ = "$Revision: 58 $" import sys import os Property changes on: pymoul/trunk/setup.py ___________________________________________________________________ Name: svn:keywords - Id Revision + Id Revisioni Modified: pymoul/trunk/setup_win32.py =================================================================== --- pymoul/trunk/setup_win32.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/setup_win32.py 2007-01-27 22:29:40 UTC (rev 89) @@ -2,7 +2,7 @@ """ __author__ = "Christian Heimes" __version__ = "$Id$" -__revision__ = "$Revision$" +__revision__ = "$Revision: 86 $" import os import sys Property changes on: pymoul/trunk/setup_win32.py ___________________________________________________________________ Name: svn:keywords - Id Revision + Id Revisioni Property changes on: pymoul/trunk/src/moul/config/tests/test_config.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/file/tests/audio.txt ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/file/tests/audiocaps.0.txt ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/file/tests/graphics.txt ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/file/tests/test_chatlog.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/file/tests/test_kiimage.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/file/tests/test_localization.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/file/tests/test_plasmalog.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/file/tests/test_wdysini.py ___________________________________________________________________ Name: svn:keywords + Id Revision Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-27 22:29:40 UTC (rev 89) @@ -1,136 +1,136 @@ -# 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 -# -"""OS dependent code for linux, mac and win32 - ->>> pids = getPids() ->>> len(pids) > 1 -True - ->>> pids = getPidNames() ->>> found = False ->>> for pid, name in pids.items(): -... if name.lower().startswith('python'): -... found = True ->>> found -True -""" -__author__ = "Christian Heimes" -__version__ = "$Id$" -__revision__ = "$Revision$" - -import os -import sys -from moul.log import getLogger -from moul.osdependent.processinfo import getPids -from moul.osdependent.processinfo import getPidNames - -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? -__CYGWIN__ = _plat('cygwin') -__LINUX__ = _plat('linux2') -__MACOSX__ = _plat('darwin') -__BSD__ = _plat('freebsd') or _plat('netbsd') or _plat('openbsd') -__POSIX__ = os.name.lower() == 'posix' -__NT__ = os.name.lower() == 'nt' -__INFO__ = (__WIN32__, __CYGWIN__, __LINUX__, __MACOSX__, __BSD__, - __POSIX__, __NT__) - -# names to import: from moul.osdependent.ID import NAME (as NAME) -NAMES = ('getMoulUserDataDir', - ('getPyMoulDataDir', '_getPyMoulDataDir'), # as - 'startMoul', 'isMoulRunning', - ) - -_marker = object() - -def _importHelper(modname, names=None, target=None): - """Import a list of variables from a module - - >>> mod = _importHelper('moul.osdependent') - >>> mod == _thismodule or mod - True - >>> vars = _importHelper('moul.osdependent', ('_marker', )) - >>> vars[0] is _marker - True - >>> class Target(object): - ... pass - >>> target = Target() - >>> vars = _importHelper('moul.osdependent', ('_marker', ), target=target) - >>> target._marker is _marker - True - >>> vars[0] is _marker - True - - >>> vars = _importHelper('moul.osdependent', (('_marker', 'another'), ), - ... target=target) - >>> target.another is _marker - True - >>> vars[0] is _marker - True - """ - mod = __import__(modname, globals(), locals(), ['']) - if names is None: - return mod - else: - vars = [] - for name in names: - if isinstance(name, (tuple, list)): - name, nameas = name - else: - nameas = name - var = getattr(mod, name) - vars.append(var) - if target is not None: - setattr(target, nameas, var) - return vars - -# XXX: what about cygwin, bsd and others? -_thismodule = sys.modules[__name__] -if __WIN32__: - _importHelper('moul.osdependent.win32', NAMES, target=_thismodule) -elif __LINUX__: - _importHelper('moul.osdependent.linux', NAMES, target=_thismodule) -elif __MACOSX__: - _importHelper('moul.osdependent.darwin', NAMES, target=_thismodule) -else: - raise RuntimeError('platform %s not supported' % sys.platform) - -def getPyMoulDataDir(check=False): - """Get pyMoul data directory - - The directory contains log files, ini files and other local stuff - """ - datadir = _getPyMoulDataDir() - if check: - if os.path.abspath(datadir) != datadir: - raise ValueError("Datadir is not absolute %s" % datadir) - if not os.path.isdir(datadir): - parent = os.path.abspath(os.path.join(datadir, os.pardir)) - if not os.path.isdir(parent): - raise ValueError("Datadir's parent dir does not exist: %s" - % par) - else: - LOG.debug("Creating pyMoul data dir %s" % datadir) - os.mkdir(datadir, 0750) - LOG.debug("Using pyMoul data dir %s" % datadir) - return datadir +# 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 +# +"""OS dependent code for linux, mac and win32 + +>>> pids = getPids() +>>> len(pids) > 1 +True + +>>> pids = getPidNames() +>>> found = False +>>> for pid, name in pids.items(): +... if name.lower().startswith('python'): +... found = True +>>> found +True +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import os +import sys +from moul.log import getLogger +from moul.osdependent.processinfo import getPids +from moul.osdependent.processinfo import getPidNames + +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? +__CYGWIN__ = _plat('cygwin') +__LINUX__ = _plat('linux2') +__MACOSX__ = _plat('darwin') +__BSD__ = _plat('freebsd') or _plat('netbsd') or _plat('openbsd') +__POSIX__ = os.name.lower() == 'posix' +__NT__ = os.name.lower() == 'nt' +__INFO__ = (__WIN32__, __CYGWIN__, __LINUX__, __MACOSX__, __BSD__, + __POSIX__, __NT__) + +# names to import: from moul.osdependent.ID import NAME (as NAME) +NAMES = ('getMoulUserDataDir', + ('getPyMoulDataDir', '_getPyMoulDataDir'), # as + 'startMoul', 'isMoulRunning', + ) + +_marker = object() + +def _importHelper(modname, names=None, target=None): + """Import a list of variables from a module + + >>> mod = _importHelper('moul.osdependent') + >>> mod == _thismodule or mod + True + >>> vars = _importHelper('moul.osdependent', ('_marker', )) + >>> vars[0] is _marker + True + >>> class Target(object): + ... pass + >>> target = Target() + >>> vars = _importHelper('moul.osdependent', ('_marker', ), target=target) + >>> target._marker is _marker + True + >>> vars[0] is _marker + True + + >>> vars = _importHelper('moul.osdependent', (('_marker', 'another'), ), + ... target=target) + >>> target.another is _marker + True + >>> vars[0] is _marker + True + """ + mod = __import__(modname, globals(), locals(), ['']) + if names is None: + return mod + else: + vars = [] + for name in names: + if isinstance(name, (tuple, list)): + name, nameas = name + else: + nameas = name + var = getattr(mod, name) + vars.append(var) + if target is not None: + setattr(target, nameas, var) + return vars + +# XXX: what about cygwin, bsd and others? +_thismodule = sys.modules[__name__] +if __WIN32__: + _importHelper('moul.osdependent.win32', NAMES, target=_thismodule) +elif __LINUX__: + _importHelper('moul.osdependent.linux', NAMES, target=_thismodule) +elif __MACOSX__: + _importHelper('moul.osdependent.darwin', NAMES, target=_thismodule) +else: + raise RuntimeError('platform %s not supported' % sys.platform) + +def getPyMoulDataDir(check=False): + """Get pyMoul data directory + + The directory contains log files, ini files and other local stuff + """ + datadir = _getPyMoulDataDir() + if check: + if os.path.abspath(datadir) != datadir: + raise ValueError("Datadir is not absolute %s" % datadir) + if not os.path.isdir(datadir): + parent = os.path.abspath(os.path.join(datadir, os.pardir)) + if not os.path.isdir(parent): + raise ValueError("Datadir's parent dir does not exist: %s" + % par) + else: + LOG.debug("Creating pyMoul data dir %s" % datadir) + os.mkdir(datadir, 0750) + LOG.debug("Using pyMoul data dir %s" % datadir) + return datadir Property changes on: pymoul/trunk/src/moul/osdependent/__init__.py ___________________________________________________________________ Name: svn:keywords + Id Revision Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/osdependent/darwin/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-01-27 22:29:40 UTC (rev 89) @@ -1,57 +1,57 @@ -# 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 -# -"""moul.osdependent.darwin -""" -__author__ = "Christian Heimes" -__version__ = "$Id$" -__revision__ = "$Revision$" - -import os -from subprocess import Popen -from moul.log import getLogger - -LOG = getLogger('moul.darwin') -LOG.critical('Darwin/Mac support is not tested') - -MOUL_DIR = "Uru Live" -EXEC_NAME = "UruLauncher" -HOME = os.environ['HOME'] - -def getMoulUserDataDir(): - """Get path of MOUL data directory - - The MOUL data directory contains log files, chatlogs, KI images and many - more things. - """ - moul_data = os.path.join(HOME, MOUL_DIR) - -def getPyMoulDataDir(): - """Get path to the pyMoul ini directory - """ - inidir= os.path.join(HOME, '.pymoul') - return inidir - -def startMoul(installdir, *args, **kwargs): - """Start MOUL - returns a Popen instance - - args are applied to the program while kwargs are applied to - subprocess.Popen() - """ - path = os.path.join(installdir, EXEC_NAME) - args = ' '.join(args) - return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) +# 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 +# +"""moul.osdependent.darwin +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import os +from subprocess import Popen +from moul.log import getLogger + +LOG = getLogger('moul.darwin') +LOG.critical('Darwin/Mac support is not tested') + +MOUL_DIR = "Uru Live" +EXEC_NAME = "UruLauncher" +HOME = os.environ['HOME'] + +def getMoulUserDataDir(): + """Get path of MOUL data directory + + The MOUL data directory contains log files, chatlogs, KI images and many + more things. + """ + moul_data = os.path.join(HOME, MOUL_DIR) + +def getPyMoulDataDir(): + """Get path to the pyMoul ini directory + """ + inidir= os.path.join(HOME, '.pymoul') + return inidir + +def startMoul(installdir, *args, **kwargs): + """Start MOUL - returns a Popen instance + + args are applied to the program while kwargs are applied to + subprocess.Popen() + """ + path = os.path.join(installdir, EXEC_NAME) + args = ' '.join(args) + return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) Property changes on: pymoul/trunk/src/moul/osdependent/darwin/__init__.py ___________________________________________________________________ Name: svn:keywords + Id Revision Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-27 22:29:40 UTC (rev 89) @@ -1,115 +1,115 @@ -# 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 -# -"""moul.osdependent.linux -""" -__author__ = "Christian Heimes" -__version__ = "$Id$" -__revision__ = "$Revision$" - -import os -from subprocess import Popen -from moul.log import getLogger - -LOG = getLogger('moul.linux') -LOG.critical('Darwin/Mac support is not tested') - -MOUL_DIR = "Uru Live" -INI_FILE = ('pyMoul', 'pymoul.ini') -EXEC_NAME = "UruLauncher" -HOME = os.environ['HOME'] -PROCESSES = ('urulauncher', 'uruexplorer') - -def getMoulUserDataDir(): - """Get path of MOUL data directory - - The MOUL data directory contains log files, chatlogs, KI images and many - more things. - """ - return os.path.join(HOME, MOUL_DIR) - -def getPyMoulDataDir(): - """Get path to the pyMoul ini directory - """ - inidir= os.path.join(HOME, '.pymoul') - return inidir - -def startMoul(installdir, *args, **kwargs): - """Start MOUL - returns a Popen instance - - args are applied to the program while kwargs are applied to - subprocess.Popen() - """ - path = os.path.join(installdir, EXEC_NAME) - args = ' '.join(args) - return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) - -def isMoulRunning(): - """Test if MOUL or the launcher is running - """ - for pid, name in getCurrentPidNames().items(): - if name.lower() in PROCESSES: - return name.lower() - return False - -# process info -# based on http://gelb.bcom.at/trac/misc/browser/processinfo -def getCurrentPids(): - """Returns current process ids - """ - pids = [] - for fname in os.listdir("/proc"): - if os.path.isdir(os.path.join("/proc", fname)): - try: - pids.append(int(fname)) - except ValueError: - continue - return pids - -def getCurrentPidDetails(): - """Returns mapping pid -> detailed informations - """ - mapping = {} - for pid in getCurrentPids(): - try: - try: - # read entiry file to avoid race condition bugs - fd = open('/proc/%i/status' % pid, 'rb') - status = fd.read().split('\n') - finally: - if fd: - fd.close() - except IoError: - continue - details = {} - for line in status: - try: - key, value = line.split(':\t') - except ValueError: - continue - details[key.lower()] = value.strip() - mapping[pid] = details - - return mapping - -def getCurrentPidNames(): - """Returns mapping pid -> name - """ - mapping = {} - for pid, details in getCurrentPidDetails().items(): - mapping[pid] = details.get('name', None) - return mapping +# 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 +# +"""moul.osdependent.linux +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import os +from subprocess import Popen +from moul.log import getLogger + +LOG = getLogger('moul.linux') +LOG.critical('Linux support is not tested') + +MOUL_DIR = "Uru Live" +INI_FILE = ('pyMoul', 'pymoul.ini') +EXEC_NAME = "UruLauncher" +HOME = os.environ['HOME'] +PROCESSES = ('urulauncher', 'uruexplorer') + +def getMoulUserDataDir(): + """Get path of MOUL data directory + + The MOUL data directory contains log files, chatlogs, KI images and many + more things. + """ + return os.path.join(HOME, MOUL_DIR) + +def getPyMoulDataDir(): + """Get path to the pyMoul ini directory + """ + inidir= os.path.join(HOME, '.pymoul') + return inidir + +def startMoul(installdir, *args, **kwargs): + """Start MOUL - returns a Popen instance + + args are applied to the program while kwargs are applied to + subprocess.Popen() + """ + path = os.path.join(installdir, EXEC_NAME) + args = ' '.join(args) + return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) + +def isMoulRunning(): + """Test if MOUL or the launcher is running + """ + for pid, name in getCurrentPidNames().items(): + if name.lower() in PROCESSES: + return name.lower() + return False + +# process info +# based on http://gelb.bcom.at/trac/misc/browser/processinfo +def getCurrentPids(): + """Returns current process ids + """ + pids = [] + for fname in os.listdir("/proc"): + if os.path.isdir(os.path.join("/proc", fname)): + try: + pids.append(int(fname)) + except ValueError: + continue + return pids + +def getCurrentPidDetails(): + """Returns mapping pid -> detailed informations + """ + mapping = {} + for pid in getCurrentPids(): + try: + try: + # read entiry file to avoid race condition bugs + fd = open('/proc/%i/status' % pid, 'rb') + status = fd.read().split('\n') + finally: + if fd: + fd.close() + except IoError: + continue + details = {} + for line in status: + try: + key, value = line.split(':\t') + except ValueError: + continue + details[key.lower()] = value.strip() + mapping[pid] = details + + return mapping + +def getCurrentPidNames(): + """Returns mapping pid -> name + """ + mapping = {} + for pid, details in getCurrentPidDetails().items(): + mapping[pid] = details.get('name', None) + return mapping Property changes on: pymoul/trunk/src/moul/osdependent/linux/__init__.py ___________________________________________________________________ Name: svn:keywords + Id Revision Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/osdependent/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/processinfo.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/src/moul/osdependent/processinfo.py 2007-01-27 22:29:40 UTC (rev 89) @@ -29,13 +29,15 @@ >>> pids > 1 True >>> isinstance(pids[0], (int, long)) +True >>> cur in pids True >>> mapping = getPidNames() >>> cur in mapping ->>> mapping[cur].lower() in cur True +>>> mapping[cur].lower() in sys.executable +True >>> getPidDetails('self')['name'] == getPidDetails(cur)['name'] True Property changes on: pymoul/trunk/src/moul/osdependent/processinfo.py ___________________________________________________________________ Name: svn:keywords + Id Revision Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/osdependent/singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-27 22:29:40 UTC (rev 89) @@ -19,55 +19,11 @@ Includes portalocker code with minor tweaks for Python 2.4+ Author: Jonathan Feinberg <jd...@po...> - Version: $Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp $ + Version: $Id$ http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65203 -Boiler plate ->>> import sys ->>> from shutil import rmtree ->>> from subprocess import Popen ->>> from StringIO import StringIO ->>> tmpdir = tempfile.mkdtemp() ->>> testfile = os.path.join(tmpdir, 'test.lck') ->>> if os.name == 'nt': -... rm = "cmd /c del" -... else: -... rm = "rm" +Unit tests for lock/unlock are in tests/test_singleapp -Create a file and lock it for this process ->>> flags = LOCK_SH | LOCK_NB ->>> fd1 = open(testfile, 'w') ->>> fn1 = fd1.fileno() ->>> lock(fd1, flags) ->>> fd1.write('testdata') ->>> os.path.isfile(testfile) -True - -Try to delete the file from another process ->>> stdout = tempfile.TemporaryFile(mode="w+") ->>> stderr = tempfile.TemporaryFile(mode="w+") ->>> popen = Popen("%s %s" % (rm, testfile), stdout=stdout, stderr=stderr) ->>> popen.wait() -0 - ->>> stdout.seek(0) ->>> out = stdout.read() ->>> if os.name == 'nt': -... out.endswith('test.lck\\n') or out -True - ->>> stderr.seek(0) ->>> stderr.read() != '' -True - ->>> os.path.isfile(testfile) -True - -Clean up ->>> unlock(fd1) ->>> fd1.close() ->>> rmtree(tmpdir) - >>> singleapp = SimpleSingleApp('testapp') >>> lckfile = singleapp.lckfile >>> if os.path.isfile(lckfile): @@ -109,13 +65,15 @@ # LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY # lowbits, highbits = 0, -65536 LOCK_SH, LOCK_NB = 0, 1 + LOCK = "dummy" elif os.name == 'posix': import fcntl - #LOCK_EX = fcntl.LOCK_EX + LOCK_EX = fcntl.LOCK_EX LOCK_SH = fcntl.LOCK_SH LOCK_NB = fcntl.LOCK_NB + LOCK = LOCK_EX | LOCK_NB else: - raise RuntimeError("PortaLocker only defined for nt and posix platforms") + raise OSError("PortaLocker only defined for nt and posix platforms") if os.name == 'nt': def lock(file, flags): @@ -128,9 +86,9 @@ pass elif os.name =='posix': def lock(file, flags): - return fcntl.flock(file.fileno(), flags) + return fcntl.lockf(file, flags) def unlock(file): - return fcntl.flock(file.fileno(), fcntl.LOCK_UN) + return fcntl.lockf(file, fcntl.LOCK_UN) class SingleAppError(OSError): pass @@ -138,7 +96,6 @@ class SimpleSingleApp(object): """A simple single instance application implemementation """ - flags = LOCK_SH | LOCK_NB def __init__(self, appname, path=TEMPDIR, user=USER, pid=PID, ext='.lck', *args): @@ -152,28 +109,24 @@ self.lckfile = self._genFilename() # register atexit function atexit.register(self.release) - + def acquire(self): """Acquire lock - + May raise an OSError """ - if os.path.isfile(self.lckfile): - try: - os.unlink(self.lckfile) - except OSError, IOError: - self._fd = None - raise SingleAppError("Another instance is already running") try: - self._fd = open(self.lckfile, 'w') - self._fd.write(str(self.pid)) - self._fd.flush() - lock(self._fd, self.flags) + self._fd = open(self.lckfile, 'w+') + lock(self._fd, LOCK) except (OSError, IOError): - self._fd.close() + LOG.exception("Failed to acquire lock") + if self._fd is not None: + self._fd.close() self._fd = None raise SingleAppError("Another instance is already running") else: + self._fd.write(str(self.pid)) + self._fd.flush() LOG.info("Create lock file %s for PID %i" % (self.lckfile, self.pid)) return self.lckfile, self.pid @@ -181,11 +134,12 @@ """Release lock """ try: - unlock(self._fd) + if self._fd is not None: + unlock(self._fd) except (SystemError, SyntaxError): raise except: - pass + LOG.exception("Error while releasin the lock") if self._fd: self._fd.close() if os.path.isfile(self.lckfile): Property changes on: pymoul/trunk/src/moul/osdependent/singleapp.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/osdependent/tests/__init__.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py ___________________________________________________________________ Name: svn:keywords + Id Revision Added: pymoul/trunk/src/moul/osdependent/tests/test_processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/tests/test_processinfo.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/tests/test_processinfo.py 2007-01-27 22:29:40 UTC (rev 89) @@ -0,0 +1,36 @@ +# 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 +# +"""moul.osdependent.processinfo +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import unittest +from doctest import DocTestSuite + +import moul.osdependent.processinfo + +def test_suite(): + return unittest.TestSuite(( + DocTestSuite('moul.osdependent.processinfo'), + )) + +if __name__ == '__main__': + unittest.main(defaultTest="test_suite") + Property changes on: pymoul/trunk/src/moul/osdependent/tests/test_processinfo.py ___________________________________________________________________ Name: svn:keywords + Id Revision Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py 2007-01-27 22:29:40 UTC (rev 89) @@ -29,11 +29,83 @@ from moul.osdependent.singleapp import unlock from moul.osdependent.singleapp import LOCK_SH, LOCK_NB +import sys +import os +import tempfile +from shutil import rmtree +from subprocess import Popen +from StringIO import StringIO +tmpdir = tempfile.mkdtemp() +testfile = os.path.join(tmpdir, 'test.lck') + +if os.name == 'nt': + rmcmd = "cmd /c del %(testfile)s" +else: + rmcmd = ("LC_ALL=C %(exe)s -c 'from fcntl import *; " + "fd = open(%(testfile)s, %(mode)s); " + "lockf(fd, LOCK_EX | LOCK_NB)'" % {'exe' : sys.executable, + 'mode' : '"a+"', 'testfile' : '"%(testfile)s"'}) + + + #singleapp = SimpleSingleApp('testapp') + #lckfile = singleapp.lckfile + #if os.path.isfile(lckfile): +#... os.unlink(fpath) + #path, pid = singleapp.acquire() + #path == lckfile +#True + #os.path.isfile(lckfile) +#True + #singleapp.checkLocked() is None +#True + #singleapp.release() + #os.path.isfile(lckfile) +#False + +class SingleAppTest(unittest.TestCase): + + def test_locking(self): + FLAGS = LOCK_SH | LOCK_NB + fd = open(testfile, 'w+') + fd.write('testdata') + fd.flush() + self.failUnless(os.path.isfile(testfile)) + lock(fd, FLAGS) + # Try to delete the file from another process + stdout = tempfile.TemporaryFile(mode="w+") + stderr = tempfile.TemporaryFile(mode="w+") + popen = Popen(rmcmd % {'testfile' : testfile}, stdout=stdout, + stderr=stderr, shell=True) + + popen.wait() + stdout.seek(0) + out = stdout.read() + if os.name == 'nt': + self.failUnlessEqual(out, '') + elif os.name =='posix': + self.failUnlessEqual(out, '') + else: + raise OSError("unsupported os") + + stderr.seek(0) + err = stderr.read() + if os.name == 'nt': + self.failUnless('IOError: [Errno 11] Resource temporarily unavailable' in err) + elif os.name =='posix': + self.failUnless('IOError: [Errno 11] Resource temporarily unavailable' in err) + else: + raise OSError("unsupported os") + + self.failUnless(os.path.isfile(testfile)) + unlock(fd) + fd.close() + rmtree(tmpdir) + def test_suite(): return unittest.TestSuite(( + unittest.makeSuite(SingleAppTest), DocTestSuite('moul.osdependent.singleapp'), )) if __name__ == '__main__': unittest.main(defaultTest="test_suite") - Property changes on: pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py ___________________________________________________________________ Name: svn:keywords + Id Revision Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-27 22:29:40 UTC (rev 89) @@ -1,74 +1,74 @@ -# 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 -# -"""moul.osdependent.win32 -""" -__author__ = "Christian Heimes" -__version__ = "$Id$" -__revision__ = "$Revision$" - -import os -from subprocess import Popen - -from moul.osdependent.win32.winpath import get_homedir as getMyDocuments -from moul.osdependent.win32.winpath import get_appdata as getAppdata -from moul.log import getLogger -from moul.osdependent.processinfo import getPidNames - -LOG = getLogger('moul.win') - -MOUL_DIR = "Uru Live" -EXEC_NAME = "UruLauncher.exe" -# lower case -PROCESSES = ("urulauncher.exe", "uruexplorer.exe") - -MYDOCS = getMyDocuments() -MYAPPDATA = getAppdata() - -def getMoulUserDataDir(): - """Get path of MOUL data directory - - The MOUL data directory contains log files, chatlogs, KI images and many - more things. - """ - moul_data = os.path.join(MYDOCS, MOUL_DIR) - return moul_data - -def getPyMoulDataDir(): - """Get path to the pyMoul ini file - """ - inidir = os.path.join(MYAPPDATA , 'pyMoul') - return inidir - -def startMoul(installdir, *args, **kwargs): - """Start MOUL - returns a Popen instance - - args are applied to the program while kwargs are applied to - subprocess.Popen() - """ - path = os.path.join(installdir, EXEC_NAME) - args = ' '.join(args) - return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) - -def isMoulRunning(): - """Test if MOUL or the launcher is running - """ - for pid, name in getPidNames().items(): - if name.lower() in PROCESSES: - return pid, name.lower() - return False - +# 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 +# +"""moul.osdependent.win32 +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import os +from subprocess import Popen + +from moul.osdependent.win32.winpath import get_homedir as getMyDocuments +from moul.osdependent.win32.winpath import get_appdata as getAppdata +from moul.log import getLogger +from moul.osdependent.processinfo import getPidNames + +LOG = getLogger('moul.win') + +MOUL_DIR = "Uru Live" +EXEC_NAME = "UruLauncher.exe" +# lower case +PROCESSES = ("urulauncher.exe", "uruexplorer.exe") + +MYDOCS = getMyDocuments() +MYAPPDATA = getAppdata() + +def getMoulUserDataDir(): + """Get path of MOUL data directory + + The MOUL data directory contains log files, chatlogs, KI images and many + more things. + """ + moul_data = os.path.join(MYDOCS, MOUL_DIR) + return moul_data + +def getPyMoulDataDir(): + """Get path to the pyMoul ini file + """ + inidir = os.path.join(MYAPPDATA , 'pyMoul') + return inidir + +def startMoul(installdir, *args, **kwargs): + """Start MOUL - returns a Popen instance + + args are applied to the program while kwargs are applied to + subprocess.Popen() + """ + path = os.path.join(installdir, EXEC_NAME) + args = ' '.join(args) + return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) + +def isMoulRunning(): + """Test if MOUL or the launcher is running + """ + for pid, name in getPidNames().items(): + if name.lower() in PROCESSES: + return pid, name.lower() + return False + Property changes on: pymoul/trunk/src/moul/osdependent/win32/__init__.py ___________________________________________________________________ Name: svn:keywords + Id Revision Name: svn:eol-style + native Property changes on: pymoul/trunk/src/moul/osdependent/win32/registry.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/osdependent/win32/winpath.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/qt/localization.py ___________________________________________________________________ Name: svn:keywords + Id Revision Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-27 21:30:28 UTC (rev 88) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-27 22:29:40 UTC (rev 89) @@ -50,7 +50,7 @@ """ LOG.info("Starting PyMoul QT UI with argv %s" % repr(args)) app = QtGui.QApplication(*args) - singleapp = SimpleSingleApp('pymoulqt', path=getPyMoulDataDir()) + singleapp = SimpleSingleApp('pymoulqt', path=getPyMoulDataDir(check=True)) try: singleapp.acquire() except OSError: Property changes on: pymoul/trunk/src/moul/qt/ui/README.txt ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/server/__init__.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/server/ping.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/server/serverlist.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/server/tests/__init__.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/server/tests/test_ping.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/server/tests/test_serverlist.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/src/moul/time/README.txt ___________________________________________________________________ Name: svn:keywords + Id Revision Name: svn:eol-style + native Property changes on: pymoul/trunk/src/moul/time/tests/test_dni.py ___________________________________________________________________ Name: svn:keywords + Id Revision Property changes on: pymoul/trunk/test.py ___________________________________________________________________ Name: svn:keywords - Id Revision + Id Revisioni Property changes on: pymoul/trunk/version.txt ___________________________________________________________________ Name: svn:keywords + Id Revisioni This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-27 21:30:32
|
Revision: 88 http://pymoul.svn.sourceforge.net/pymoul/?rev=88&view=rev Author: tiran Date: 2007-01-27 13:30:28 -0800 (Sat, 27 Jan 2007) Log Message: ----------- Better process info API Modified Paths: -------------- pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/osdependent/win32/__init__.py Added Paths: ----------- pymoul/trunk/src/moul/osdependent/processinfo.py Removed Paths: ------------- pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 19:03:20 UTC (rev 87) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-27 21:30:28 UTC (rev 88) @@ -17,11 +17,11 @@ # """OS dependent code for linux, mac and win32 ->>> pids = getCurrentPids() +>>> pids = getPids() >>> len(pids) > 1 True ->>> pids = getCurrentPidNames() +>>> pids = getPidNames() >>> found = False >>> for pid, name in pids.items(): ... if name.lower().startswith('python'): @@ -36,6 +36,8 @@ import os import sys from moul.log import getLogger +from moul.osdependent.processinfo import getPids +from moul.osdependent.processinfo import getPidNames LOG = getLogger('moul.osdependent') @@ -57,7 +59,6 @@ NAMES = ('getMoulUserDataDir', ('getPyMoulDataDir', '_getPyMoulDataDir'), # as 'startMoul', 'isMoulRunning', - 'getCurrentPids', 'getCurrentPidNames', ) _marker = object() Added: pymoul/trunk/src/moul/osdependent/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/processinfo.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/processinfo.py 2007-01-27 21:30:28 UTC (rev 88) @@ -0,0 +1,235 @@ +# 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 + +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)) +>>> cur in pids +True + +>>> mapping = getPidNames() +>>> cur in mapping +>>> mapping[cur].lower() in cur +True + +>>> getPidDetails('self')['name'] == getPidDetails(cur)['name'] +True +>>> getPidDetails(cur)['name'] == mapping[cur] +True +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import os +import sys + +_plat = sys.platform.startswith +if _plat('linux'): + PLAT = 'linux' + import os.path +elif _plat('win') or _plat('cygwin'): + PLAT = 'win' + 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 +#elif _plat('darwin'): +# pass +else: + raise OSError("OS %s is not supported" % os.name) + +NULL = "\x00" + +class LinuxProcReader(object): + """Get process informations under Linux by reading /proc + + Tested under Linux, may work on other POSIX os with /proc, too. + """ + + def getPids(self): + """Get a list of pids + """ + pids = [] + for name in os.listdir('/proc'): + if os.path.isdir('/proc/' + name): + try: + pids.append(int(name)) + except ValueError: + pass + return pids + + def getPidNames(self): + """Get a list of pid -> name + """ + mapping = {} + for pid in self.getPids(): + name = self._readProcStatus(pid, searchkey='name') + if name is not None: + mapping[pid] = name + return mapping + + def getPidDetails(self, pid): + """Get detailed informations about a process + """ + details = self._readProcStatus(pid) + details.update(self._readProcOther(pid)) + details['cmdline'] = self._readProcCmdline(pid) + return details + + def _readProcStatus(self, 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 = {} + try: + # read entiry file to avoid race conditions + lines = open('/proc/%s/status' % pid, 'r').readlines() + except IOError: + 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 + + def _readProcCmdline(self, pid): + """Read cmdline informations for pid and returns a list similar to sys.argv + """ + try: + # read entiry file to avoid race conditions + data = open('/proc/%s/cmdline' % pid, 'r').read() + except IOError: + return None + return data.split(NULL) + + def _readProcOther(self, 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('/proc/%s/cwd' % pid), + 'exe' : os.path.realpath('/proc/%s/exe' % 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 + """ + def getPids(self): + """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] + + def getPidNames(self): + """Get a list of pid -> name + """ + hModule = c_ulong() + count = c_ulong() + modname = c_buffer(51) + mapping = [] + for pid in self.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)) + name = u"".join([c for c in modname if c != NULL]) + modname[:] = sizeof(modname) * NULL + KERNEL.CloseHandle(hProcess) + mapping[pid] = name + + return mapping + + def getPidDetails(self, 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)) + name = u"".join([c for c in modname if c != NULL]) + KERNEL.CloseHandle(hProcess) + return {'name' : name} + + +# Initialize global methods +if PLAT == 'linux': + _enumProcesses = LinuxProcReader() +elif PLAT == 'win': + _enumProcesses = WinEnumProcesses() + +getPids = _enumProcesses.getPids +getPidNames = _enumProcesses.getPidNames +getPidDetails = _enumProcesses.getPidDetails + +if __name__ == '__main__': + print getPidNames() + print getPidDetails('self') Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 19:03:20 UTC (rev 87) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-27 21:30:28 UTC (rev 88) @@ -26,8 +26,8 @@ from moul.osdependent.win32.winpath import get_homedir as getMyDocuments from moul.osdependent.win32.winpath import get_appdata as getAppdata -from moul.osdependent.win32.enumprocesses import enumProcesses from moul.log import getLogger +from moul.osdependent.processinfo import getPidNames LOG = getLogger('moul.win') @@ -67,18 +67,8 @@ def isMoulRunning(): """Test if MOUL or the launcher is running """ - for pid, name in getCurrentPidNames().items(): + for pid, name in getPidNames().items(): if name.lower() in PROCESSES: - return name.lower() + return pid, name.lower() return False -def getCurrentPids(): - """Returns mapping pid -> name - """ - return enumProcesses().keys() - - -def getCurrentPidNames(): - """Returns mapping pid -> name - """ - return enumProcesses() Deleted: pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py 2007-01-26 19:03:20 UTC (rev 87) +++ pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py 2007-01-27 21:30:28 UTC (rev 88) @@ -1,66 +0,0 @@ -""" -Enumerates active processes as seen under windows Task Manager on Win NT/2k/XP using PSAPI.dll -(new api for processes) and using ctypes.Use it as you please. - -Based on information from http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q175030&ID=KB;EN-US;Q175030 - -By Eric Koome -email ek...@ya... -license GPL - -http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/305279 -Title: getting process information on windows -Last Updated: 2004/09/22 -Version no: 1.3 - -Changed by Christian Heimes -""" - -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 -NULL = '\x00' - -def enumProcesses(): - """Enumerate processes on Windows using psapi.dll - - @return: A mapping of pid(long) -> process name(unicode) - """ - result = {} - arr = c_ulong * 256 - lpidProcess = arr() - cb = sizeof(lpidProcess) - cbNeeded = c_ulong() - hModule = c_ulong() - count = c_ulong() - modname = c_buffer(51) - - # 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 - pidProcess = [pid for pid in lpidProcess][:nReturned] - - for pid in pidProcess: - # 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)) - - name = u"".join([c for c in modname if c != NULL]) - result[pid] = name - - modname[:] = sizeof(modname) * NULL - KERNEL.CloseHandle(hProcess) - - return result - -if __name__ == '__main__': - from pprint import pprint - pprint(EnumProcesses()) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 19:03:25
|
Revision: 87 http://pymoul.svn.sourceforge.net/pymoul/?rev=87&view=rev Author: tiran Date: 2007-01-26 11:03:20 -0800 (Fri, 26 Jan 2007) Log Message: ----------- Status message More log cleanups More logging Modified Paths: -------------- pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/singleapp.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/moulqt.py pymoul/trunk/src/moul/qt/ui/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.ui Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/log.py 2007-01-26 19:03:20 UTC (rev 87) @@ -72,8 +72,9 @@ """ global mhdlr global fhdlr - mhdlr.setTarget(fhdlr) - mhdlr.flush() + if mhdlr: + mhdlr.setTarget(fhdlr) + mhdlr.flush() root.removeHandler(mhdlr) del mhdlr @@ -114,11 +115,15 @@ else: _installMemoryHdlr() _systemInfo() + +def createLogfile(): + """Create log file and redirect stdout/stderr to logfile + """ _installFileHdlr() _removeMemoryHdlr() # Redirect stdout and stderr to logger when running as frozen app - #sys.stdout = LoggingStdout(getLogger('stdout').info) - #sys.stderr = LoggingStdout(getLogger('stderr').error) + sys.stdout = LoggingStdout(getLogger('stdout').info) + sys.stderr = LoggingStdout(getLogger('stderr').error) __LOG_SIGNALS__ = not __FROZEN__ def signalLogDecorator(__logger__): Modified: pymoul/trunk/src/moul/osdependent/singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-26 19:03:20 UTC (rev 87) @@ -87,11 +87,14 @@ __version__ = "$Id$" __revision__ = "$Revision$" +import atexit import os import getpass +from logging import getLogger import tempfile -import atexit +LOG = getLogger('singleapp') + TEMPDIR = tempfile.gettempdir() USER = getpass.getuser() PID = os.getpid() @@ -170,7 +173,9 @@ self._fd.close() self._fd = None raise SingleAppError("Another instance is already running") - return self.lckfile, self.pid + else: + LOG.info("Create lock file %s for PID %i" % (self.lckfile, self.pid)) + return self.lckfile, self.pid def release(self): """Release lock @@ -184,6 +189,7 @@ if self._fd: self._fd.close() if os.path.isfile(self.lckfile): + LOG.info("Remove lock file %s" % self.lckfile) os.unlink(self.lckfile) def checkLocked(self): Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 19:03:20 UTC (rev 87) @@ -83,15 +83,32 @@ self._documents_init() # run checker + self._moulrunning = None self._moulrunning_thread = MoulRunningThread() self.connect(self._moulrunning_thread, SIGNAL('moulIsRunning(bool)'), self.on_moulIsRunning) self._moulrunning_thread.startChecker(5.0) # check now and every 5 seconds @signalLogDecorator(LOG) - def on_moulIsRunning(self, bool): - pass - + def on_moulIsRunning(self, boolean): + sb = self.statusbar + boolean = bool(boolean) + if boolean is not self._moulrunning: + self._moulrunning = boolean + self.systemtray.setToolTip + if boolean: + msg = self.trUtf8("MOUL is running") + sb.showMessage(msg) + self.systemtray.setToolTip(msg) + self.systemtray.showMessage(self.trUtf8('MOUL'), msg, + QtGui.QSystemTrayIcon.Information, 10000) + else: + msg = self.trUtf8("MOUL is not running") + sb.showMessage(msg) + self.systemtray.setToolTip(msg) + self.systemtray.showMessage(self.trUtf8('MOUL'), msg, + QtGui.QSystemTrayIcon.Information, 10000) + def _notimplemented(self): """TODO: remove me """ Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 19:03:20 UTC (rev 87) @@ -31,8 +31,24 @@ from moul.osdependent.singleapp import SimpleSingleApp from moul.config import getPyMoulDataDir from moul.osdependent import isMoulRunning +from moul.log import createLogfile +from moul.log import getLogger +LOG = getLogger('moul.qt') + def main(*args): + """Main application + + Flow diagram: + * create app + * check if other instance of pymoulqt is running + o exit app if another instance is running + * create log file handler + * check if URU is running + o exit if URU is running + * Show the main window + """ + LOG.info("Starting PyMoul QT UI with argv %s" % repr(args)) app = QtGui.QApplication(*args) singleapp = SimpleSingleApp('pymoulqt', path=getPyMoulDataDir()) try: @@ -43,16 +59,22 @@ """An instance of pyMoul QT is already running!""") mb.exec_() sys.exit(1) - if isMoulRunning(): - mb = criticalMessageBox(app, - "URU is running", - """URU is running! Please close Uru or Uru Launcher first.""") - mb.exec_() - sys.exit(2) + + createLogfile() + +# if isMoulRunning(): +# mb = criticalMessageBox(app, +# "URU is running", +# """URU is running! Please close Uru or Uru Launcher first.""") +# mb.exec_() +# sys.exit(2) + LOG.info("Invoking PyMoul QT MainWindow") mainWindow = MainWindow() mainWindow.show() - return app.exec_() + err = app.exec_() + LOG.info("Exiting PyMoul QT UI with status %i" % err) + return err if __name__ == '__main__': err = main(sys.argv) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-26 19:03:20 UTC (rev 87) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src\moul\qt\ui\mainwindow.ui' # -# Created: Fri Jan 26 14:28:09 2007 +# Created: Fri Jan 26 19:48:46 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -14,7 +14,7 @@ def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.setWindowModality(QtCore.Qt.NonModal) - MainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,460,530).size()).expandedTo(MainWindow.minimumSizeHint())) + MainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,460,534).size()).expandedTo(MainWindow.minimumSizeHint())) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(0),QtGui.QSizePolicy.Policy(0)) sizePolicy.setHorizontalStretch(0) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.ui =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-26 19:03:20 UTC (rev 87) @@ -10,7 +10,7 @@ <x>0</x> <y>0</y> <width>460</width> - <height>530</height> + <height>534</height> </rect> </property> <property name="sizePolicy" > This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 18:46:01
|
Revision: 86 http://pymoul.svn.sourceforge.net/pymoul/?rev=86&view=rev Author: tiran Date: 2007-01-26 10:30:56 -0800 (Fri, 26 Jan 2007) Log Message: ----------- More cleanups: removed unused processinfo module Removed dependency on pywin32 again. Apparently windows locks the file Modified Paths: -------------- pymoul/trunk/setup_win32.py pymoul/trunk/src/moul/osdependent/singleapp.py pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py Removed Paths: ------------- pymoul/trunk/src/moul/osdependent/processinfo.py Modified: pymoul/trunk/setup_win32.py =================================================================== --- pymoul/trunk/setup_win32.py 2007-01-26 17:37:52 UTC (rev 85) +++ pymoul/trunk/setup_win32.py 2007-01-26 18:30:56 UTC (rev 86) @@ -71,9 +71,7 @@ pexe['includes'] = ['sip', 'PyQt4', 'encodings', 'encodings.*', 'moul.osdependent.win32', 'moul.osdependent.win32.*'] # SSL currently not in use but imported by socket - pexe['excludes'] = ['_ssl'] - # added by platform but not yet required - #pexe['excludes'].extend(('win32pipe', 'win32api', 'win32con', 'win32evtlog')) + pexe['excludes'] = ['_ssl', 'win32pipe', 'win32evtlog', 'win32file', 'win32api'] # added by logging.handlers.SMTPHandler but not yet required pexe['excludes'].append('smtplib') # UPX Deleted: pymoul/trunk/src/moul/osdependent/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/processinfo.py 2007-01-26 17:37:52 UTC (rev 85) +++ pymoul/trunk/src/moul/osdependent/processinfo.py 2007-01-26 18:30:56 UTC (rev 86) @@ -1,219 +0,0 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-1 -*- -"""Process info - -Based on http://gelb.bcom.at/trac/misc/browser/processinfo - -Modified and optimized by Christian Heimes -""" - -import sys -import os - -__all__ = ['PLATFORM', 'UnsupportedOsError', 'getCurrentPids', - 'getCurrentPidNames', 'getCurrentPidDetails'] - -class UnsupportedOsError(NotImplementedError): - pass - -PLATFORM = None - -_plat = sys.platform.startswith -if _plat('win'): - PLATFORM = 'win' - win32process = None - ctypes = None - import csv - try: - import win32process - except ImportError: - try: - import ctypes - except ImportError: - pass -elif _plat('linux2') or _plat('cygwin'): - PLATFORM = 'linux' # Linux or Cygwin -elif _plat('darwin'): - # XXX: unsupported - PLATFORM = 'mac' # Mac OS X -elif _plat('freebsd') or _plat('netbsd') or _plat('openbsd'): - # XXX: unsupported - PLATFORM = 'bsd' # *BSD -else: - PLATFORM = 'unknown' - raise UnsupportedOsError(sys.platform) - -# **************************************************************************** -# Linux / cygwin implementation - -def _getCurrentPids_linux(): - """ - Returns current process-id's. - - :return: list with process-id's. - """ - pids = [] - for fname in os.listdir("/proc"): - if os.path.isdir(os.path.join("/proc", fname)): - try: - pids.append(int(fname)) - except ValueError: - continue - return pids - -def _getCurrentPidDetails_linux(): - """Returns mapping pid -> detailed informations - """ - mapping = {} - for pid in getCurrentPids(): - try: - try: - # read entiry file to avoid race condition bugs - fd = open('/proc/%i/status' % pid, 'rb') - status = fd.read().split('\n') - finally: - if fd: - fd.close() - except IoError: - continue - details = {} - for line in status: - try: - key, value = line.split(':\t') - except ValueError: - continue - details[key.lower()] = value.strip() - mapping[pid] = details - - return mapping - -def _getCurrentPidNames_linux(): - """Returns mapping pid -> name - """ - mapping = {} - for pid, details in getCurrentPidDetails().items(): - mapping[pid] = details.get('name', None) - return mapping - - -# **************************************************************************** -# Windows / win32 implementaton - -def _getCurrentPids_win(): - """ - Returns current process-id's. - - :return: List with process-id's. - """ - if win32process is not None: - return list(win32process.EnumProcesses()) - elif ctypes is not None: - # ctypes is installed --> try psapi.dll - psapi = ct.windll.psapi - arr = ct.c_long * 1024 - process_ids = arr() - cb = ct.sizeof(process_ids) - bytes_returned = ct.c_ulong() - psapi.EnumProcesses(ct.byref(process_ids), cb, ct.byref(bytes_returned)) - return sorted(list(set(process_ids))) - else: - csvlines = [] - current_pids = [] - for line in os.popen("tasklist.exe /fo csv /nh"): - line = line.strip() - if line: - csvlines.append(line) - for line in csv.reader(csvlines): - current_pids.append(int(line[1])) - if not csvlines: - raise NotImplementedError("tasklist.exe not found (>WinXP)") - return current_pids - -def _getCurrentPidNames_win(): - """Returns mapping pid -> name - """ - mapping = {} - for pid, details in getCurrentPidDetails().items(): - mapping[pid] = details.get('name', None) - return mapping - -def _getCurrentPidDetails_win(): - """ - Returns processinfos. (pid, name and size_kb) - """ - result = {} - - # tasklist.exe runs on Windows XP and higher. (To parse the ouput of - # tasklist.exe is faster than WMI.) - csvlines = [] - for line in os.popen("tasklist.exe /fo csv /nh"): - line = line.strip() - if line: - csvlines.append(line) - for line in csv.reader(csvlines): - pid = int(line[1]) - details = { - "name": line[0].decode("cp850"), # to unicode - "pid": pid, - } - value = "".join( - char for char in line[4] - if char.isdigit() - ) - details["size_kb"] = int(value) - retdict[pid] = details - if not csvlines: - try: - from win32com.client import GetObject - # pywin32 is installed --> use WMI - wmi = GetObject('winmgmts:') - processes = wmi.InstancesOf('Win32_Process') - for process in processes: - pid = int(process.Properties_("ProcessId").value) - details = { - "name": process.Properties_("Name").value, - "pid": pid, - "size_kb": int(process.Properties_("WorkingSetSize").value) / 1000 - } - retdict[pid] = details - except ImportError: - raise NotImplementedError("No tasklist.exe and no WMI.") - return retdict - -# **************************************************************************** -# general - -def unsupported(): - """Platform not supported - """ - raise UnsupportedOsError(PLATFORM) -unsupported.__unsupported__ = True - -def _initialize(): - mod = sys.modules[__name__] - for name in ('getCurrentPids','getCurrentPidDetails', 'getCurrentPidNames'): - func = getattr(mod, "_%s_%s" % (name, PLATFORM), None) - if func is None: - func = unsupported - else: - func.__name__ = name - setattr(mod, name, func) -_initialize() - -def main(): - """Testing""" - - from pprint import pformat - # Current PIDs - current_pids = getCurrentPids() - print "Current PIDs: %s" % pformat(current_pids) - print - print "Current PID Count: %s" % len(current_pids) - print - - print "Current PIDs with names: %s" % pformat(getCurrentPidNames()) - print - -if __name__ == "__main__": - main() - Modified: pymoul/trunk/src/moul/osdependent/singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-26 17:37:52 UTC (rev 85) +++ pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-26 18:30:56 UTC (rev 86) @@ -25,11 +25,12 @@ Boiler plate >>> import sys >>> from shutil import rmtree ->>> from subprocess import call +>>> from subprocess import Popen +>>> from StringIO import StringIO >>> tmpdir = tempfile.mkdtemp() >>> testfile = os.path.join(tmpdir, 'test.lck') >>> if os.name == 'nt': -... rm = "del" +... rm = "cmd /c del" ... else: ... rm = "rm" @@ -39,20 +40,29 @@ >>> fn1 = fd1.fileno() >>> lock(fd1, flags) >>> fd1.write('testdata') +>>> os.path.isfile(testfile) +True Try to delete the file from another process ->>> try: -... retcode = call("%s %s" % (rm, testfile)) -... except: -... typ, value, tb = sys.exc_info() -... del tb -... else: -... print "Should have raised an error!" +>>> stdout = tempfile.TemporaryFile(mode="w+") +>>> stderr = tempfile.TemporaryFile(mode="w+") +>>> popen = Popen("%s %s" % (rm, testfile), stdout=stdout, stderr=stderr) +>>> popen.wait() +0 -On Windows the error is WindowsError based on OSError ->>> issubclass(typ, OSError) or typ +>>> stdout.seek(0) +>>> out = stdout.read() +>>> if os.name == 'nt': +... out.endswith('test.lck\\n') or out True +>>> stderr.seek(0) +>>> stderr.read() != '' +True + +>>> os.path.isfile(testfile) +True + Clean up >>> unlock(fd1) >>> fd1.close() @@ -86,17 +96,19 @@ USER = getpass.getuser() PID = os.getpid() +# PYWIN32: Apparently windows locks a file automatically if os.name == 'nt': - import win32con - import win32file - import pywintypes - LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK - LOCK_SH = 0 # the default - LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY - lowbits, highbits = 0, -65536 +# import win32con +# import win32file +# import pywintypes +# LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK +# LOCK_SH = 0 # the default +# LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY +# lowbits, highbits = 0, -65536 + LOCK_SH, LOCK_NB = 0, 1 elif os.name == 'posix': import fcntl - LOCK_EX = fcntl.LOCK_EX + #LOCK_EX = fcntl.LOCK_EX LOCK_SH = fcntl.LOCK_SH LOCK_NB = fcntl.LOCK_NB else: @@ -104,11 +116,13 @@ if os.name == 'nt': def lock(file, flags): - hfile = win32file._get_osfhandle(file.fileno()) - return win32file.LockFileEx(hfile, flags, lowbits, highbits, pywintypes.OVERLAPPED()) + #hfile = win32file._get_osfhandle(file.fileno()) + #return win32file.LockFileEx(hfile, flags, lowbits, highbits, pywintypes.OVERLAPPED()) + pass def unlock(file): - hfile = win32file._get_osfhandle(file.fileno()) - return win32file.UnlockFileEx(hfile, lowbits, highbits, pywintypes.OVERLAPPED()) + #hfile = win32file._get_osfhandle(file.fileno()) + #return win32file.UnlockFileEx(hfile, lowbits, highbits, pywintypes.OVERLAPPED()) + pass elif os.name =='posix': def lock(file, flags): return fcntl.flock(file.fileno(), flags) @@ -141,6 +155,12 @@ May raise an OSError """ + if os.path.isfile(self.lckfile): + try: + os.unlink(self.lckfile) + except OSError, IOError: + self._fd = None + raise SingleAppError("Another instance is already running") try: self._fd = open(self.lckfile, 'w') self._fd.write(str(self.pid)) Modified: pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py 2007-01-26 17:37:52 UTC (rev 85) +++ pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py 2007-01-26 18:30:56 UTC (rev 86) @@ -27,7 +27,7 @@ from moul.osdependent.singleapp import SimpleSingleApp from moul.osdependent.singleapp import lock from moul.osdependent.singleapp import unlock -from moul.osdependent.singleapp import LOCK_EX, LOCK_SH, LOCK_NB +from moul.osdependent.singleapp import LOCK_SH, LOCK_NB def test_suite(): return unittest.TestSuite(( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 17:37:54
|
Revision: 85 http://pymoul.svn.sourceforge.net/pymoul/?rev=85&view=rev Author: tiran Date: 2007-01-26 09:37:52 -0800 (Fri, 26 Jan 2007) Log Message: ----------- Finally a fast and working enumProcess function ... :) Modified Paths: -------------- pymoul/trunk/src/moul/osdependent/win32/__init__.py pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/moulqt.py Removed Paths: ------------- pymoul/trunk/src/moul/osdependent/win32/miniwinshell.py pymoul/trunk/src/moul/osdependent/win32/processinfo.py pymoul/trunk/src/moul/osdependent/win32/wmi.py Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 17:37:52 UTC (rev 85) @@ -24,11 +24,9 @@ import os from subprocess import Popen -from moul.osdependent.win32.miniwinshell import my_documents as getMyDocuments -from moul.osdependent.win32.miniwinshell import application_data as getAppdata -#from moul.osdependent.win32.winpath import get_homedir as getMyDocuments -#from moul.osdependent.win32.winpath import get_appdata as getAppdata -from moul.osdependent.win32 import wmi +from moul.osdependent.win32.winpath import get_homedir as getMyDocuments +from moul.osdependent.win32.winpath import get_appdata as getAppdata +from moul.osdependent.win32.enumprocesses import enumProcesses from moul.log import getLogger LOG = getLogger('moul.win') @@ -38,7 +36,6 @@ # lower case PROCESSES = ("urulauncher.exe", "uruexplorer.exe") -MYCOMPUTER = None # wmi instance MYDOCS = getMyDocuments() MYAPPDATA = getAppdata() @@ -78,18 +75,10 @@ def getCurrentPids(): """Returns mapping pid -> name """ - global MYCOMPUTER - if MYCOMPUTER is None: - # XXX: extremely slow, also see getCurrentPidNames - MYCOMPUTER = wmi.WMI() - return [process.ProcessId for process in MYCOMPUTER.Win32_Process()] + return enumProcesses().keys() + def getCurrentPidNames(): """Returns mapping pid -> name """ - global MYCOMPUTER - if MYCOMPUTER is None: - MYCOMPUTER = wmi.WMI() - return dict([(process.ProcessId, process.Name) - for process in MYCOMPUTER.Win32_Process() - ]) + return enumProcesses() Modified: pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py 2007-01-26 17:37:52 UTC (rev 85) @@ -7,57 +7,60 @@ By Eric Koome email ek...@ya... license GPL + +http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/305279 +Title: getting process information on windows +Last Updated: 2004/09/22 +Version no: 1.3 + +Changed by Christian Heimes """ -#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/305279 -#Title: getting process information on windows -#Submitter: Eric Koome (other recipes) -#Last Updated: 2004/09/22 -#Version no: 1.3 -#Category: -from ctypes import * +from ctypes import windll, c_ulong, sizeof, c_buffer, byref -#PSAPI.DLL -psapi = windll.psapi -#Kernel32.DLL -kernel = windll.kernel32 +PSAPI = windll.psapi +KERNEL = windll.kernel32 +PROCESS_QUERY_INFORMATION = 0x0400 +PROCESS_VM_READ = 0x0010 +PROCESS_FLAGS = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ +NULL = '\x00' -def EnumProcesses(): +def enumProcesses(): + """Enumerate processes on Windows using psapi.dll + + @return: A mapping of pid(long) -> process name(unicode) + """ + result = {} arr = c_ulong * 256 - lpidProcess= arr() + lpidProcess = arr() cb = sizeof(lpidProcess) cbNeeded = c_ulong() hModule = c_ulong() count = c_ulong() - modname = c_buffer(30) - PROCESS_QUERY_INFORMATION = 0x0400 - PROCESS_VM_READ = 0x0010 + modname = c_buffer(51) - #Call Enumprocesses to get hold of process id's - psapi.EnumProcesses(byref(lpidProcess), - cb, - byref(cbNeeded)) + # 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 + pidProcess = [pid for pid in lpidProcess][:nReturned] - #Number of processes returned - nReturned = cbNeeded.value/sizeof(c_ulong()) - - pidProcess = [i for i in lpidProcess][:nReturned] - for pid in pidProcess: - - #Get handle to the process based on PID - hProcess = kernel.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - False, pid) + # 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)) - print "".join([ i for i in modname if i != '\x00']) + PSAPI.EnumProcessModules(hProcess, byref(hModule), + sizeof(hModule), byref(count)) + PSAPI.GetModuleBaseNameA(hProcess, hModule.value, modname, + sizeof(modname)) + + name = u"".join([c for c in modname if c != NULL]) + result[pid] = name - #-- Clean up - for i in range(modname._length_): - modname[i]='\x00' - - kernel.CloseHandle(hProcess) + modname[:] = sizeof(modname) * NULL + KERNEL.CloseHandle(hProcess) + return result + if __name__ == '__main__': - EnumProcesses() \ No newline at end of file + from pprint import pprint + pprint(EnumProcesses()) Deleted: pymoul/trunk/src/moul/osdependent/win32/miniwinshell.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/miniwinshell.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/miniwinshell.py 2007-01-26 17:37:52 UTC (rev 85) @@ -1,141 +0,0 @@ -"""winshell - convenience functions to access Windows shell functionality - -Certain aspects of the Windows user interface are grouped by - Microsoft as Shell functions. These include the Desktop, shortcut - icons, special folders (such as My Documents) and a few other things. - -These are mostly available via the shell module of the win32all - extensions, but whenever I need to use them, I've forgotten the - various constants and so on. - -Several of the shell items have two variants: personal and common, - or User and All Users. These refer to systems with profiles in use: - anything from NT upwards, and 9x with Profiles turned on. Where - relevant, the Personal/User version refers to that owned by the - logged-on user and visible only to that user; the Common/All Users - version refers to that maintained by an Administrator and visible - to all users of the system. - -(c) Tim Golden <win...@ti...> 25th November 2003 -Licensed under the (GPL-compatible) MIT License: -http://www.opensource.org/licenses/mit-license.php - -9th Nov 2005 0.2 . License changed to MIT - . Added functionality using SHFileOperation -25th Nov 2003 0.1 . Initial release by Tim Golden - - -THIS IS A STRIPPED DOWN VERSION OF WINSHELL -It contains only small subset to keep the build small -""" - -__VERSION__ = "0.2small" - -from win32com.shell import shell, shellcon -#import pythoncom - -# -# Although this can be done in one call, Win9x didn't -# support it, so I added this workaround. -# -def get_path (folder_id): - return shell.SHGetPathFromIDList (shell.SHGetSpecialFolderLocation (0, folder_id)) - -def desktop (common=0): - "What folder is equivalent to the current desktop?" - return get_path ((shellcon.CSIDL_DESKTOP, shellcon.CSIDL_COMMON_DESKTOPDIRECTORY)[common]) - -def common_desktop (): -# -# Only here because already used in code -# - return desktop (common=1) - -def application_data (common=0): - "What folder holds application configuration files?" - return get_path ((shellcon.CSIDL_APPDATA, shellcon.CSIDL_COMMON_APPDATA)[common]) - -def favourites (common=0): - "What folder holds the Explorer favourites shortcuts?" - return get_path ((shellcon.CSIDL_FAVORITES, shellcon.CSIDL_COMMON_FAVORITES)[common]) -bookmarks = favourites - -def start_menu (common=0): - "What folder holds the Start Menu shortcuts?" - return get_path ((shellcon.CSIDL_STARTMENU, shellcon.CSIDL_COMMON_STARTMENU)[common]) - -def programs (common=0): - "What folder holds the Programs shortcuts (from the Start Menu)?" - return get_path ((shellcon.CSIDL_PROGRAMS, shellcon.CSIDL_COMMON_PROGRAMS)[common]) - -def startup (common=0): - "What folder holds the Startup shortcuts (from the Start Menu)?" - return get_path ((shellcon.CSIDL_STARTUP, shellcon.CSIDL_COMMON_STARTUP)[common]) - -def personal_folder (): - "What folder holds the My Documents files?" - return get_path (shellcon.CSIDL_PERSONAL) -my_documents = personal_folder - -def recent (): - "What folder holds the Documents shortcuts (from the Start Menu)?" - return get_path (shellcon.CSIDL_RECENT) - -def sendto (): - "What folder holds the SendTo shortcuts (from the Context Menu)?" - return get_path (shellcon.CSIDL_SENDTO) - -def CreateShortcut (Path, Target, Arguments = "", StartIn = "", Icon = ("",0), Description = ""): - """Create a Windows shortcut: - - Path - As what file should the shortcut be created? - Target - What command should the desktop use? - Arguments - What arguments should be supplied to the command? - StartIn - What folder should the command start in? - Icon - (filename, index) What icon should be used for the shortcut? - Description - What description should the shortcut be given? - - eg - CreateShortcut ( - Path=os.path.join (desktop (), "PythonI.lnk"), - Target=r"c:\python\python.exe", - Icon=(r"c:\python\python.exe", 0), - Description="Python Interpreter" - ) - """ - sh = pythoncom.CoCreateInstance ( - shell.CLSID_ShellLink, - None, - pythoncom.CLSCTX_INPROC_SERVER, - shell.IID_IShellLink - ) - - sh.SetPath (Target) - sh.SetDescription (Description) - sh.SetArguments (Arguments) - sh.SetWorkingDirectory (StartIn) - sh.SetIconLocation (Icon[0], Icon[1]) - - persist = sh.QueryInterface (pythoncom.IID_IPersistFile) - persist.Save (Path, 1) - -if __name__ == '__main__': - try: - print 'Desktop =>', desktop () - print 'Common Desktop =>', desktop (1) - print 'Application Data =>', application_data () - print 'Common Application Data =>', application_data (1) - print 'Bookmarks =>', bookmarks () - print 'Common Bookmarks =>', bookmarks (1) - print 'Start Menu =>', start_menu () - print 'Common Start Menu =>', start_menu (1) - print 'Programs =>', programs () - print 'Common Programs =>', programs (1) - print 'Startup =>', startup () - print 'Common Startup =>', startup (1) - print 'My Documents =>', my_documents () - print 'Recent =>', recent () - print 'SendTo =>', sendto () - finally: - raw_input ("Press enter...") - Deleted: pymoul/trunk/src/moul/osdependent/win32/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/processinfo.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/processinfo.py 2007-01-26 17:37:52 UTC (rev 85) @@ -1,34 +0,0 @@ -#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303339 -#Title: getting process information on windows -#Submitter: John Nielsen (other recipes) -#Last Updated: 2004/09/03 -#Version no: 1.0 -#Category: System - -import win32pdh, string, win32api - -def procids(): - #each instance is a process, you can have multiple processes w/same name - junk, instances = win32pdh.EnumObjectItems(None,None,'process', win32pdh.PERF_DETAIL_WIZARD) - proc_ids=[] - proc_dict={} - for instance in instances: - if instance in proc_dict: - proc_dict[instance] = proc_dict[instance] + 1 - else: - proc_dict[instance]=0 - for instance, max_instances in proc_dict.items(): - for inum in xrange(max_instances+1): - hq = win32pdh.OpenQuery() # initializes the query handle - path = win32pdh.MakeCounterPath( (None,'process',instance, None, inum,'ID Process') ) - counter_handle=win32pdh.AddCounter(hq, path) - win32pdh.CollectQueryData(hq) #collects data for the counter - type, val = win32pdh.GetFormattedCounterValue(counter_handle, win32pdh.PDH_FMT_LONG) - proc_ids.append((instance,str(val))) - win32pdh.CloseQuery(hq) - - proc_ids.sort() - return proc_ids - - -print procids() \ No newline at end of file Deleted: pymoul/trunk/src/moul/osdependent/win32/wmi.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/wmi.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/wmi.py 2007-01-26 17:37:52 UTC (rev 85) @@ -1,1246 +0,0 @@ -## -# wmi - a lightweight Python wrapper around Microsoft's WMI interface -# -# Windows Management Instrumentation (WMI) is Microsoft's answer to -# the DMTF's Common Information Model. It allows you to query just -# about any conceivable piece of information from any computer which -# is running the necessary agent and over which have you the -# necessary authority. -# -# The implementation is by means of COM/DCOM and most of the examples -# assume you're running one of Microsoft's scripting technologies. -# Fortunately, Mark Hammond's pywin32 has pretty much all you need -# for a workable Python adaptation. I haven't tried any of the fancier -# stuff like Async calls and so on, so I don't know if they'd work. -# -# Since the COM implementation doesn't give much away to Python -# programmers, I've wrapped it in some lightweight classes with -# some getattr / setattr magic to ease the way. In particular: -# -# <ul> -# <li> -# The _wmi_namespace object itself will determine its classes -# and allow you to return all instances of any of them by -# using its name as an attribute. As an additional shortcut, -# you needn't specify the Win32_; if the first lookup fails -# it will try again with a Win32_ on the front: -# -# <pre class="code"> -# disks = wmi.WMI ().Win32_LogicalDisk () -# </pre> -# -# In addition, you can specify what would become the WHERE clause -# as keyword parameters: -# -# <pre class="code"> -# fixed_disks = wmi.WMI ().Win32_LogicalDisk (DriveType = 3) -# </pre> -# </li> -# -# <li> -# The objects returned by a WMI lookup are wrapped in a Python -# class which determines their methods and classes and allows -# you to access them as though they were Python classes. The -# methods only allow named parameters. -# -# <pre class="code"> -# for p in wmi.WMI ().Win32_Process (): -# if p.Name.lower () == 'notepad.exe': -# p.Terminate (Result=1) -# </pre> -# </li> -# -# <li> -# Doing a print on one of the WMI objects will result in its -# GetObjectText_ method being called, which usually produces -# a meaningful printout of current values. -# The repr of the object will include its full WMI path, -# which lets you get directly to it if you need to. -# </li> -# -# <li> -# You can get the associators and references of an object as -# a list of python objects by calling the associators () and -# references () methods on a WMI Python object. -# NB Don't do this on a Win32_ComputerSystem object; it will -# take all day and kill your machine! -# -# <pre class="code"> -# for p in wmi.WMI ().Win32_Process (): -# if p.Name.lower () == 'notepad.exe': -# for r in p.references (): -# print r.Name -# </pre> -# </li> -# -# <li> -# WMI classes (as opposed to instances) are first-class -# objects, so you can get hold of a class, and call -# its methods or set up a watch against it. -# -# <pre class="code"> -# process = wmi.WMI ().Win32_Process -# process.Create (CommandLine="notepad.exe") -# </pre> -# -# </li> -# -# <li> -# To make it easier to use in embedded systems and py2exe-style -# executable wrappers, the module will not force early Dispatch. -# To do this, it uses a handy hack by Thomas Heller for easy access -# to constants. -# </li> -# -# <li> -# Typical usage will be: -# -# <pre class="code"> -# import wmi -# -# vodev1 = wmi.WMI ("vodev1") -# for disk in vodev1.Win32_LogicalDisk (): -# if disk.DriveType == 3: -# space = 100 * long (disk.FreeSpace) / long (disk.Size) -# print "%s has %d%% free" % (disk.Name, space) -# </pre> -# </li> -# -# </ul> -# -# Many thanks, obviously to Mark Hammond for creating the win32all -# extensions, but also to Alex Martelli and Roger Upole, whose -# c.l.py postings pointed me in the right direction. -# Thanks especially in release 1.2 to Paul Tiemann for his code -# contributions and robust testing. -# -# (c) Tim Golden - mail at timgolden.me.uk 5th June 2003 -# Licensed under the (GPL-compatible) MIT License: -# http://www.opensource.org/licenses/mit-license.php -# -# For change history see CHANGELOG.TXT -## -try: - True, False -except NameError: - True = 1 - False = 0 - -try: - object -except NameError: - class object: pass - -__VERSION__ = "1.2.1" - -_DEBUG = False - -import sys -import re -from win32com.client import GetObject, Dispatch -import pywintypes - -class ProvideConstants (object): - """ - A class which, when called on a win32com.client.Dispatch object, - provides lazy access to constants defined in the typelib. - - They can be accessed as attributes of the _constants property. - From Thomas Heller on c.l.py - """ - def __init__(self, comobj): - "@param comobj A COM object whose typelib constants are to be exposed" - comobj.__dict__["_constants"] = self - # Get the typelibrary's typecomp interface - self.__typecomp = \ - comobj._oleobj_.GetTypeInfo().GetContainingTypeLib()[0].GetTypeComp() - - def __getattr__(self, name): - if name.startswith("__") and name.endswith("__"): - raise AttributeError, name - result = self.__typecomp.Bind(name) - # Bind returns a 2-tuple, first item is TYPEKIND, - # the second item has the value - if not result[0]: - raise AttributeError, name - return result[1].value - -obj = GetObject ("winmgmts:") -ProvideConstants (obj) - -wbemErrInvalidQuery = obj._constants.wbemErrInvalidQuery -wbemErrTimedout = obj._constants.wbemErrTimedout -wbemFlagReturnImmediately = obj._constants.wbemFlagReturnImmediately -wbemFlagForwardOnly = obj._constants.wbemFlagForwardOnly - -def handle_com_error (error_info): - """Convenience wrapper for displaying all manner of COM errors. - Raises a x_wmi exception with more useful information attached - - @param error_info The structure attached to a pywintypes.com_error - """ - hresult_code, hresult_name, additional_info, parameter_in_error = error_info - exception_string = ["%s - %s" % (hex (hresult_code), hresult_name)] - if additional_info: - wcode, source_of_error, error_description, whlp_file, whlp_context, scode = additional_info - exception_string.append (" Error in: %s" % source_of_error) - exception_string.append (" %s - %s" % (hex (scode), error_description.strip ())) - raise x_wmi, "\n".join (exception_string) - -def from_time (year=None, month=None, day=None, hours=None, minutes=None, seconds=None, microseconds=None, timezone=None): - """ - Convenience wrapper to take a series of date/time elements and return a WMI time - of the form yyyymmddHHMMSS.mmmmmm+UUU. All elements may be int, string or - omitted altogether. If omitted, they will be replaced in the output string - by a series of stars of the appropriate length. - - @param year The year element of the date/time - @param month The month element of the date/time - @param day The day element of the date/time - @param hours The hours element of the date/time - @param minutes The minutes element of the date/time - @param seconds The seconds element of the date/time - @param microseconds The microseconds element of the date/time - @param timezone The timeezone element of the date/time - - @return A WMI datetime string of the form: yyyymmddHHMMSS.mmmmmm+UUU - """ - def str_or_stars (i, length): - if i is None: - return "*" * length - else: - return str (i).rjust (length, "0") - - wmi_time = "" - wmi_time += str_or_stars (year, 4) - wmi_time += str_or_stars (month, 2) - wmi_time += str_or_stars (day, 2) - wmi_time += str_or_stars (hours, 2) - wmi_time += str_or_stars (minutes, 2) - wmi_time += str_or_stars (seconds, 2) - wmi_time += "." - wmi_time += str_or_stars (microseconds, 6) - wmi_time += str_or_stars (timezone, 4) - - return wmi_time - -def to_time (wmi_time): - """ - Convenience wrapper to take a WMI datetime string of the form - yyyymmddHHMMSS.mmmmmm+UUU and return a 9-tuple containing the - individual elements, or None where string contains placeholder - stars. - - @param wmi_time The WMI datetime string in yyyymmddHHMMSS.mmmmmm+UUU format - - @return A 9-tuple of (year, month, day, hours, minutes, seconds, microseconds, timezone) - """ - def int_or_none (s, start, end): - try: - return int (s[start:end]) - except ValueError: - return None - - year = int_or_none (wmi_time, 0, 4) - month = int_or_none (wmi_time, 4, 6) - day = int_or_none (wmi_time, 6, 8) - hours = int_or_none (wmi_time, 8, 10) - minutes = int_or_none (wmi_time, 10, 12) - seconds = int_or_none (wmi_time, 12, 14) - microseconds = int_or_none (wmi_time, 15, 21) - timezone = wmi_time[21:] - - return year, month, day, hours, minutes, seconds, microseconds, timezone - -# -# Exceptions -# -class x_wmi (Exception): - pass - -class x_wmi_invalid_query (x_wmi): - pass - -class x_wmi_timed_out (x_wmi): - pass - -class x_wmi_no_namespace (x_wmi): - pass - -WMI_EXCEPTIONS = { - wbemErrInvalidQuery : x_wmi_invalid_query, - wbemErrTimedout : x_wmi_timed_out -} - -def _set (obj, attribute, value): - """ - Helper function to add an attribute directly into the instance - dictionary, bypassing possible __getattr__ calls - - @param obj Any python object - @param attribute String containing attribute name - @param value Any python object - """ - obj.__dict__[attribute] = value - -class _wmi_method: - """ - A currying sort of wrapper around a WMI method name. It - abstract's the method's parameters and can be called like - a normal Python object passing in the parameter values. - - Output parameters are returned from the call as a tuple. - In addition, the docstring is set up as the method's - signature, including an indication as to whether any - given parameter is expecting an array, and what - special privileges are required to call the method. - """ - - def __init__ (self, ole_object, method_name): - """ - @param ole_object The WMI class/instance whose method is to be called - @param method_name The name of the method to be called - """ - try: - self.ole_object = Dispatch (ole_object) - self.method = ole_object.Methods_ (method_name) - self.qualifiers = {} - for q in self.method.Qualifiers_: - self.qualifiers[q.Name] = q.Value - self.provenance = "\n".join (self.qualifiers.get ("MappingStrings", [])) - - self.in_parameters = self.method.InParameters - self.out_parameters = self.method.OutParameters - if self.in_parameters is None: - self.in_parameter_names = [] - else: - self.in_parameter_names = [(i.Name, i.IsArray) for i in self.in_parameters.Properties_] - if self.out_parameters is None: - self.out_parameter_names = [] - else: - self.out_parameter_names = [(i.Name, i.IsArray) for i in self.out_parameters.Properties_] - - doc = "%s (%s) => (%s)" % ( - method_name, - ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.in_parameter_names]), - ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.out_parameter_names]) - ) - privileges = self.qualifiers.get ("Privileges", []) - if privileges: - doc += " | Needs: " + ", ".join (privileges) - self.__doc__ = doc - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __call__ (self, **kwargs): - """ - Execute the call to a WMI method, returning - a tuple (even if is of only one value) containing - the out and return parameters. - """ - try: - if self.in_parameters: - parameter_names = {} - for name, is_array in self.in_parameter_names: - parameter_names[name] = is_array - - parameters = self.in_parameters - for k, v in kwargs.items (): - is_array = parameter_names.get (k) - if is_array is None: - raise AttributeError, "%s is not a valid parameter for %s" % (k, self.__doc__) - else: - if is_array: - try: list (v) - except TypeError: raise TypeError, "%s must be iterable" % k - - parameters.Properties_ (k).Value = v - - result = self.ole_object.ExecMethod_ (self.method.Name, self.in_parameters) - else: - result = self.ole_object.ExecMethod_ (self.method.Name) - - results = [] - for name, is_array in self.out_parameter_names: - value = result.Properties_ (name).Value - if is_array: - # - # Thanks to Jonas Bjering for bug report and path - # - results.append (list (value or [])) - else: - results.append (value) - return tuple (results) - - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __repr__ (self): - return "<function %s>" % self.__doc__ - -# -# class _wmi_object -# -class _wmi_object: - "A lightweight wrapper round an OLE WMI object" - - def __init__ (self, ole_object, instance_of=None, fields=[]): - try: - _set (self, "ole_object", ole_object) - _set (self, "_instance_of", instance_of) - _set (self, "properties", {}) - _set (self, "methods", {}) - - if self._instance_of: - if fields: - for field in fields: - self.properties[field] = None - else: - _set (self, "properties", self._instance_of.properties.copy ()) - _set (self, "methods", self._instance_of.methods) - else: - for p in ole_object.Properties_: - self.properties[p.Name] = None - for m in ole_object.Methods_: - self.methods[m.Name] = None - - _set (self, "_properties", self.properties.keys ()) - _set (self, "_methods", self.methods.keys ()) - - _set (self, "qualifiers", {}) - for q in self.ole_object.Qualifiers_: - self.qualifiers[q.Name] = q.Value - _set (self, "is_association", self.qualifiers.has_key ("Association")) - - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __str__ (self): - """ - For a call to print [object] return the OLE description - of the properties / values of the object - """ - try: - return self.ole_object.GetObjectText_ () - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __repr__ (self): - """ - Indicate both the fact that this is a wrapped WMI object - and the WMI object's own identifying class. - """ - try: - return "<%s: %s>" % (self.__class__.__name__, str (self.Path_.Path)) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def _cached_properties (self, attribute): - if self.properties[attribute] is None: - self.properties[attribute] = self.ole_object.Properties_ (attribute) - return self.properties[attribute] - - def _cached_methods (self, attribute): - if self.methods[attribute] is None: - self.methods[attribute] = _wmi_method (self.ole_object, attribute) - return self.methods[attribute] - - def __getattr__ (self, attribute): - """ - Attempt to pass attribute calls to the proxied COM object. - If the attribute is recognised as a property, return its value; - if it is recognised as a method, return a method wrapper which - can then be called with parameters; otherwise pass the lookup - on to the underlying object. - """ - try: - if self.properties.has_key (attribute): - value = self._cached_properties (attribute).Value - # - # If this is an association, its properties are - # actually the paths to the two aspects of the - # association, so translate them automatically - # into WMI objects. - # - if self.is_association: - return WMI (moniker=value) - else: - return value - elif self.methods.has_key (attribute): - return self._cached_methods (attribute) - else: - return getattr (self.ole_object, attribute) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __setattr__ (self, attribute, value): - """ - If the attribute to be set is valid for the proxied - COM object, set that objects's parameter value; if not, - raise an exception. - """ - try: - if self.properties.has_key (attribute): - self._cached_properties (attribute).Value = value - if self.ole_object.Path_.Path: - self.ole_object.Put_ () - else: - raise AttributeError, attribute - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __eq__ (self, other): - """ - Use WMI's CompareTo_ to compare this object with - another. Don't try to do anything if the other - object is not a wmi object. It might be possible - to compare this object's unique key with a string - or something, but this doesn't seem to be universal - enough to merit a special case. - """ - if isinstance (other, self.__class__): - return self.ole_object.CompareTo_ (other.ole_object) - else: - raise x_wmi, "Can't compare a WMI object with something else" - - def put (self): - self.ole_object.Put_ () - - def set (self, **kwargs): - """ - Set several properties of the underlying object - at one go. This is particularly useful in combination - with the new () method below. However, an instance - which has been spawned in this way won't have enough - information to write pack, so only try if the - instance has a path. - """ - if kwargs: - try: - for attribute, value in kwargs.items (): - if self.properties.has_key (attribute): - self._cached_properties (attribute).Value = value - else: - raise AttributeError, attribute - # - # Only try to write the attributes - # back if the object exists. - # - if self.ole_object.Path_.Path: - self.ole_object.Put_ () - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def path (self): - """ - Return the WMI URI to this object. Can be used to - determine the path relative to the parent namespace. eg, - - <pre class="code"> - pp0 = wmi.WMI ().Win32_ParallelPort ()[0] - print pp0.path ().RelPath - </pre> - """ - try: - return self.ole_object.Path_ - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def derivation (self): - """Return a tuple representing the object derivation for - this object, with the most specific object first. eg, - - pp0 = wmi.WMI ().Win32_ParallelPort ()[0] - print ' <- '.join (pp0.derivation ()) - """ - try: - return self.ole_object.Derivation_ - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def associators (self, wmi_association_class="", wmi_result_class=""): - """Return a list of objects related to this one, optionally limited - either by association class (ie the name of the class which relates - them) or by result class (ie the name of the class which would be - retrieved) - - <pre class="code"> -c = wmi.WMI () -pp = c.Win32_ParallelPort ()[0] - -for i in pp.associators (wmi_association_class="Win32_PortResource"): - print i - -for i in pp.associators (wmi_result_class="Win32_PnPEntity"): - print i - </pre> - """ - try: - return [ - _wmi_object (i) for i in \ - self.ole_object.Associators_ ( - strAssocClass=wmi_association_class, - strResultClass=wmi_result_class - ) - ] - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def references (self, wmi_class=""): - """Return a list of associations involving this object, optionally - limited by the result class (the name of the association class). - - NB Associations are treated specially; although WMI only returns - the string corresponding to the instance of each associated object, - this module will automatically convert that to the object itself. - - <pre class="code"> - c = wmi.WMI () - sp = c.Win32_SerialPort ()[0] - - for i in sp.references (): - print i - - for i in sp.references (wmi_class="Win32_SerialPortSetting"): - print i - </pre> - """ - try: - return [_wmi_object (i) for i in self.ole_object.References_ (strResultClass=wmi_class)] - except pywintypes.com_error, error_info: - handle_com_error (error_info) - -# -# class _wmi_class -# -class _wmi_class (_wmi_object): - """Currying class to assist in issuing queries against - a WMI namespace. The idea is that when someone issues - an otherwise unknown method against the WMI object, if - it matches a known WMI class a query object will be - returned which may then be called with one or more params - which will form the WHERE clause. eg, - - <pre class="code"> - c = wmi.WMI () - c_drive = c.Win32_LogicalDisk (Name='C:') - </pre> - """ - def __init__ (self, namespace, wmi_class): - _wmi_object.__init__ (self, wmi_class) - _set (self, "_namespace", namespace) - _set (self, "_class_name", wmi_class.Path_.Class) - - def query (self, fields=[], **where_clause): - """Make it slightly easier to query against the class, - by calling the namespace's query with the class preset. - Won't work if the class has been instantiated directly. - """ - if self._namespace is None: - raise x_wmi_no_namespace, "You cannot query directly from a WMI class" - - try: - field_list = ", ".join (fields) or "*" - wql = "SELECT " + field_list + " FROM " + self._class_name - if where_clause: - wql += " WHERE " + " AND ". join (["%s = '%s'" % (k, v) for k, v in where_clause.items ()]) - return self._namespace.query (wql, self, fields) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - __call__ = query - - def watch_for ( - self, - notification_type=None, - delay_secs=1, - **where_clause - ): - if self._namespace is None: - raise x_wmi_no_namespace, "You cannot watch directly from a WMI class" - - return self._namespace.watch_for ( - notification_type=notification_type, - wmi_class=self._class_name, - delay_secs=delay_secs, - **where_clause - ) - - def instances (self): - """Return a list of instances of the WMI class - """ - try: - return [_wmi_object (instance, self) for instance in self.Instances_ ()] - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def new (self, **kwargs): - """This is the equivalent to the raw-WMI SpawnInstance_ - method. Note that there are relatively few uses for - this, certainly fewer than you might imagine. Most - classes which need to create a new *real* instance - of themselves, eg Win32_Process, offer a .Create - method. SpawnInstance_ is generally reserved for - instances which are passed as parameters to such - .Create methods, a common example being the - Win32_SecurityDescriptor, passed to Win32_Share.Create - and other instances which need security. - - The example here is Win32_ProcessStartup, which - controls the shown/hidden state etc. of a new - Win32_Process instance. - - <pre class="code"> - import win32con - import wmi - c = wmi.WMI () - startup = c.Win32_ProcessStartup.new (ShowWindow=win32con.SW_SHOWMINIMIZED) - pid, retval = c.Win32_Process.Create ( - CommandLine="notepad.exe", - ProcessStartupInformation=startup - ) - </pre> - - NB previous versions of this module, used this function - to create new process. This is *not* a good example - of its use; it is better handled with something like - the example above. - """ - try: - obj = _wmi_object (self.SpawnInstance_ (), self) - obj.set (**kwargs) - return obj - except pywintypes.com_error, error_info: - handle_com_error (error_info) - -# -# class _wmi_result -# -class _wmi_result: - """Simple, data only result for targeted WMI queries which request - data only result classes via fetch_as_classes. - """ - def __init__(self, obj, attributes): - if attributes: - for attr in attributes: - self.__dict__[attr] = obj.Properties_ (attr).Value - else: - for p in obj.Properties_: - attr = p.Name - self.__dict__[attr] = obj.Properties_(attr).Value - -# -# class WMI -# -class _wmi_namespace: - """A WMI root of a computer system. The classes attribute holds a list - of the classes on offer. This means you can explore a bit with - things like this: - - <pre class="code"> - c = wmi.WMI () - for i in c.classes: - if "user" in i.lower (): - print i - </pre> - """ - def __init__ (self, namespace, find_classes): - _set (self, "_namespace", namespace) - # - # wmi attribute preserved for backwards compatibility - # - _set (self, "wmi", namespace) - - # Initialise the "classes" attribute, to avoid infinite recursion in the - # __getattr__ method (which uses it). - self.classes = {} - # - # Pick up the list of classes under this namespace - # so that they can be queried, and used as though - # properties of the namespace by means of the __getattr__ - # hook below. - # If the namespace does not support SubclassesOf, carry on - # regardless - # - if find_classes: - try: - self.classes.update (self.subclasses_of ()) - except AttributeError: - pass - - def __repr__ (self): - return "<_wmi_namespace: %s>" % self.wmi - - def __str__ (self): - return repr (self) - - def get (self, moniker): - try: - return _wmi_object (self.wmi.Get (moniker)) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def handle (self): - """The raw OLE object representing the WMI namespace""" - return self._namespace - - def subclasses_of (self, root="", regex=r".*"): - classes = {} - for c in self._namespace.SubclassesOf (root): - klass = c.Path_.Class - if re.match (regex, klass): - classes[klass] = None - return classes - - def instances (self, class_name): - """Return a list of instances of the WMI class. This is - (probably) equivalent to querying with no qualifiers. - - <pre class="code"> - system.instances ("Win32_LogicalDisk") - # should be the same as - system.Win32_LogicalDisk () - </pre> - """ - try: - return [_wmi_object (obj) for obj in self._namespace.InstancesOf (class_name)] - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def new (self, wmi_class, **kwargs): - """This is now implemented by a call to _wmi_namespace.new (qv)""" - return getattr (self, wmi_class).new (**kwargs) - - new_instance_of = new - - def _raw_query (self, wql): - """Execute a WQL query and return its raw results. Use the flags - recommended by Microsoft to achieve a read-only, semi-synchronous - query where the time is taken while looping through. Should really - be a generator, but ... - NB Backslashes need to be doubled up. - """ - flags = wbemFlagReturnImmediately | wbemFlagForwardOnly - wql = wql.replace ("\\", "\\\\") - if _DEBUG: print "_raw_query(wql):", wql - try: - return self._namespace.ExecQuery (strQuery=wql, iFlags=flags) - except pywintypes.com_error, (hresult, hresult_text, additional, param_in_error): - raise WMI_EXCEPTIONS.get (hresult, x_wmi (hresult)) - - def query (self, wql, instance_of=None, fields=[]): - """Perform an arbitrary query against a WMI object, and return - a list of _wmi_object representations of the results. - """ - return [ _wmi_object (obj, instance_of, fields) for obj in self._raw_query(wql) ] - - def fetch_as_classes (self, wmi_classname, fields=(), **where_clause): - """Build and execute a wql query to fetch the specified list of fields from - the specified wmi_classname + where_clause, then return the results as - a list of simple class instances with attributes matching fields_list. - - If fields is left empty, select * and pre-load all class attributes for - each class returned. - """ - wql = "SELECT %s FROM %s" % (fields and ", ".join (fields) or "*", wmi_classname) - if where_clause: - wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) - return [_wmi_result (obj, fields) for obj in self._raw_query(wql)] - - def fetch_as_lists (self, wmi_classname, fields, **where_clause): - """Build and execute a wql query to fetch the specified list of fields from - the specified wmi_classname + where_clause, then return the results as - a list of lists whose values correspond fields_list. - """ - wql = "SELECT %s FROM %s" % (", ".join (fields), wmi_classname) - if where_clause: - wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) - results = [] - for obj in self._raw_query(wql): - results.append ([obj.Properties_ (field).Value for field in fields]) - return results - - def watch_for ( - self, - raw_wql=None, - notification_type=None, - wmi_class=None, - delay_secs=1, - **where_clause - ): - """Set up an event tracker on a WMI event. This function - returns an wmi_watcher which can be called to get the - next event. eg, - - <pre class="code"> - c = wmi.WMI () - - raw_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'" - watcher = c.watch_for (raw_wql=raw_wql) - while 1: - process_created = watcher () - print process_created.Name - - # or - - watcher = c.watch_for ( - notification_type="Creation", - wmi_class="Win32_Process", - delay_secs=2, - Name='calc.exe' - ) - calc_created = watcher () - </pre> - - Now supports timeout on the call to watcher, eg: - - <pre class="code"> - import pythoncom - import wmi - c = wmi.WMI (privileges=["Security"]) - watcher1 = c.watch_for ( - notification_type="Creation", - wmi_class="Win32_NTLogEvent", - Type="error" - ) - watcher2 = c.watch_for ( - notification_type="Creation", - wmi_class="Win32_NTLogEvent", - Type="warning" - ) - - while 1: - try: - error_log = watcher1 (500) - except wmi.x_wmi_timed_out: - pythoncom.PumpWaitingMessages () - else: - print error_log - - try: - warning_log = watcher2 (500) - except wmi.x_wmi_timed_out: - pythoncom.PumpWaitingMessages () - else: - print warning_log - </pre> - """ - class_name = wmi_class - if raw_wql: - wql = raw_wql - else: - if where_clause: - where = " AND " + " AND ".join (["TargetInstance.%s = '%s'" % (k, v) for k, v in where_clause.items ()]) - else: - where = "" - wql = \ - "SELECT * FROM __Instance%sEvent WITHIN %d WHERE TargetInstance ISA '%s' %s" % \ - (notification_type, delay_secs, class_name, where) - - if _DEBUG: print wql - - try: - return _wmi_watcher (self._namespace.ExecNotificationQuery (wql)) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __getattr__ (self, attribute): - """Offer WMI classes as simple attributes. Pass through any untrapped - unattribute to the underlying OLE object. This means that new or - unmapped functionality is still available to the module user. - """ - # - # Don't try to match against known classes as was previously - # done since the list may not have been requested - # (find_classes=False). - # - try: - return self._cached_classes (attribute) - except pywintypes.com_error, error_info: - try: - return self._cached_classes ("Win32_" + attribute) - except pywintypes.com_error, error_info: - return getattr (self._namespace, attribute) - - def _cached_classes (self, class_name): - """Standard caching helper which keeps track of classes - already retrieved by name and returns the existing object - if found. If this is the first retrieval, store it and - pass it back - """ - if self.classes.get (class_name) is None: - self.classes[class_name] = _wmi_class (self, self._namespace.Get (class_name)) - return self.classes[class_name] - -# -# class _wmi_watcher -# -class _wmi_watcher: - """Helper class for WMI.watch_for below (qv)""" - - def __init__ (self, wmi_event): - self.wmi_event = wmi_event - - def __call__ (self, timeout_ms=-1): - """When called, return the instance which caused the event. Supports - timeout in milliseconds (defaulting to infinite). If the watcher - times out, x_wmi_timed_out is raised. This makes it easy to support - watching for multiple objects. - """ - try: - return _wmi_object (self.wmi_event.NextEvent (timeout_ms).Properties_ ("TargetInstance").Value) - except pywintypes.com_error, error_info: - hresult_code, hresult_name, additional_info, parameter_in_error = error_info - if additional_info: - wcode, source_of_error, error_description, whlp_file, whlp_context, scode = additional_info - if scode == wbemErrTimedout: - raise x_wmi_timed_out - handle_com_error (error_info) - -PROTOCOL = "winmgmts:" -IMPERSONATION_LEVEL = "impersonate" -AUTHENTICATION_LEVEL = "default" -NAMESPACE = "root/cimv2" -def connect ( - computer=".", - impersonation_level="", - authentication_level="", - authority="", - privileges="", - moniker="", - wmi=None, - namespace="", - suffix="", - user="", - password="", - find_classes=True, - debug=False -): - """The WMI constructor can either take a ready-made moniker or as many - parts of one as are necessary. Eg, - - <pre class="code"> - c = wmi.WMI (moniker="winmgmts:{impersonationLevel=Delegate}//remote") - - # or - - c = wmi.WMI (computer="remote", privileges=["!RemoteShutdown", "Security"]) - </pre> - - I daren't link to a Microsoft URL; they change so often. Try Googling for - WMI construct moniker and see what it comes back with. - - For complete control, a named argument "wmi" can be supplied, which - should be a SWbemServices object, which you create yourself. Eg, - - <pre class="code"> - loc = win32com.client.Dispatch("WbemScripting.SWbemLocator") - svc = loc.ConnectServer(...) - c = wmi.WMI(wmi=svc) - </pre> - - This is the only way of connecting to a remote computer with a different - username, as the moniker syntax does not allow specification of a user - name. - - If the "wmi" parameter is supplied, all other parameters are ignored. - """ - global _DEBUG - _DEBUG = debug - - # - # If namespace is a blank string, leave - # it unaltered as it might to trying to - # access the root namespace - # - #if namespace is None: - # namespace = NAMESPACE - - try: - if wmi: - obj = wmi - - elif moniker: - if not moniker.startswith (PROTOCOL): - moniker = PROTOCOL + moniker - if _DEBUG: print moniker - obj = GetObject (moniker) - - else: - if user: - if impersonation_level or authentication_level or privileges or suffix: - raise x_wmi, "You can't specify an impersonation, authentication or privilege as well as a username" - else: - obj = connect_server ( - server=computer, - namespace=namespace, - user=user, - password=password, - authority=authority - ) - - else: - moniker = construct_moniker ( - computer=computer, - impersonation_level=impersonation_level or IMPERSONATION_LEVEL, - authentication_level=authentication_level or AUTHENTICATION_LEVEL, - authority=authority, - privileges=privileges, - namespace=namespace, - suffix=suffix - ) - if _DEBUG: print moniker - obj = GetObject (moniker) - - wmi_type = get_wmi_type (obj) - - if wmi_type == "namespace": - return _wmi_namespace (obj, find_classes) - elif wmi_type == "class": - return _wmi_class (None, obj) - elif wmi_type == "instance": - return _wmi_object (obj) - else: - raise x_wmi, "Unknown moniker type" - - except pywintypes.com_error, error_info: - handle_com_error (error_info) - -WMI = connect - -def construct_moniker ( - computer=None, - impersonation_level="Impersonate", - authentication_level="Default", - authority=None, - privileges=None, - namespace=None, - suffix=None -): - security = [] - if impersonation_level: security.append ("impersonationLevel=%s" % impersonation_level) - if authentication_level: security.append ("authenticationLevel=%s" % authentication_level) - # - # Use of the authority descriptor is invalid on the local machine - # - if authority and computer: security.append ("authority=%s" % authority) - if privileges: security.append ("(%s)" % ", ".join (privileges)) - - moniker = [PROTOCOL] - if security: moniker.append ("{%s}/" % ",".join (security)) - if computer: moniker.append ("/%s/" % computer) - if namespace: - parts = re.split (r"[/\\]", namespace) - if parts[0] != 'root': - parts.insert (0, "root") - moniker.append ("/".join (parts)) - if suffix: moniker.append (":%s" % suffix) - return "".join (moniker) - -def get_wmi_type (obj): - try: - path = obj.Path_ - except AttributeError: - return "namespace" - else: - if path.IsClass: - return "class" - else: - return "instance" - -def connect_server ( - server, - namespace = "", - user = "", - password = "", - locale = "", - authority = "", - security_flags = 0, - named_value_set = None -): - """Return a remote server running WMI - - server - name of the server - namespace - namespace to connect to: defaults to whatever's defined as default - user - username to connect as, either local or domain (dom\name or user@domain for XP) - password: leave blank to use current context - locale: desired locale in form MS_XXXX (eg MS_409 for Am En) - authority: either "Kerberos:" or an NT domain. Not needed if included in user - security_flags: if 0, connect will wait forever; if 0x80, connect will timeout at 2 mins - named_value_set: typically empty, otherwise a context-specific SWbemNamedValueSet - - <pre class="code"> - c = wmi.WMI (wmi=wmi.connect_server (server="remote_machine", user="myname", password="mypassword")) - </pre> - """ - if _DEBUG: - print server - print namespace - print user - print password - print locale - print authority - print security_flags - print named_value_set - - return Dispatch ("WbemScripting.SWbemLocator").\ - ConnectServer ( - server, - namespace, - user, - password, - locale, - authority, - security_flags, - named_value_set - ) - -def Registry ( - computer=None, - impersonation_level="Impersonate", - authentication_level="Default", - authority=None, - privileges=None, - moniker=None -): - - if not moniker: - moniker = construct_moniker ( - computer=computer, - impersonation_level=impersonation_level, - authentication_level=authentication_level, - authority=authority, - privileges=privileges, - namespace="default", - suffix="StdRegProv" - ) - - try: - return _wmi_object (GetObject (moniker)) - - except pywintypes.com_error, error_info: - handle_com_error (error_info) - -# -# From a post to python-win32 by Sean -# -def machines_in_domain (domain_name): - adsi = Dispatch ("ADsNameSpaces") - nt = adsi.GetObject ("","WinNT:") - result = nt.OpenDSObject ("WinNT://%s" % domain_name, "", "", 0) - result.Filter = ["computer"] - domain = [] - for machine in result: - domain.append (machine.Name) - return domain - -# -# Typical use test -# -if __name__ == '__main__': - system = WMI () - for my_computer in system.Win32_ComputerSystem (): - print "Disks on", my_computer.Name - for disk in system.Win32_LogicalDisk (): - print disk.Caption, disk.Description, disk.ProviderName or "" - Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 17:37:52 UTC (rev 85) @@ -86,7 +86,7 @@ self._moulrunning_thread = MoulRunningThread() self.connect(self._moulrunning_thread, SIGNAL('moulIsRunning(bool)'), self.on_moulIsRunning) - self._moulrunning_thread.startChecker(10.0) # check now and every 10 seconds + self._moulrunning_thread.startChecker(5.0) # check now and every 5 seconds @signalLogDecorator(LOG) def on_moulIsRunning(self, bool): @@ -569,7 +569,7 @@ def run(self): while True: - result = True #isMoulRunning() + result = isMoulRunning() if result: self.emit(SIGNAL('moulIsRunning(bool)'), True) else: Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 17:37:52 UTC (rev 85) @@ -43,12 +43,12 @@ """An instance of pyMoul QT is already running!""") mb.exec_() sys.exit(1) - #if isMoulRunning(): - # mb = criticalMessageBox(app, - # "URU is running", - # """URU is running! Please close Uru or Uru Launcher first.""") - # mb.exec_() - # sys.exit(2) + if isMoulRunning(): + mb = criticalMessageBox(app, + "URU is running", + """URU is running! Please close Uru or Uru Launcher first.""") + mb.exec_() + sys.exit(2) mainWindow = MainWindow() mainWindow.show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 16:40:36
|
Revision: 84 http://pymoul.svn.sourceforge.net/pymoul/?rev=84&view=rev Author: tiran Date: 2007-01-26 08:40:35 -0800 (Fri, 26 Jan 2007) Log Message: ----------- Add two other modules about process infos (could be useful but I have to test them) Added Paths: ----------- pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py pymoul/trunk/src/moul/osdependent/win32/processinfo.py Added: pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py 2007-01-26 16:40:35 UTC (rev 84) @@ -0,0 +1,63 @@ +""" +Enumerates active processes as seen under windows Task Manager on Win NT/2k/XP using PSAPI.dll +(new api for processes) and using ctypes.Use it as you please. + +Based on information from http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q175030&ID=KB;EN-US;Q175030 + +By Eric Koome +email ek...@ya... +license GPL +""" +#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/305279 +#Title: getting process information on windows +#Submitter: Eric Koome (other recipes) +#Last Updated: 2004/09/22 +#Version no: 1.3 +#Category: + +from ctypes import * + +#PSAPI.DLL +psapi = windll.psapi +#Kernel32.DLL +kernel = windll.kernel32 + +def EnumProcesses(): + arr = c_ulong * 256 + lpidProcess= arr() + cb = sizeof(lpidProcess) + cbNeeded = c_ulong() + hModule = c_ulong() + count = c_ulong() + modname = c_buffer(30) + PROCESS_QUERY_INFORMATION = 0x0400 + PROCESS_VM_READ = 0x0010 + + #Call Enumprocesses to get hold of process id's + psapi.EnumProcesses(byref(lpidProcess), + cb, + byref(cbNeeded)) + + #Number of processes returned + nReturned = cbNeeded.value/sizeof(c_ulong()) + + pidProcess = [i for i in lpidProcess][:nReturned] + + for pid in pidProcess: + + #Get handle to the process based on PID + hProcess = kernel.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + False, pid) + if hProcess: + psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count)) + psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname)) + print "".join([ i for i in modname if i != '\x00']) + + #-- Clean up + for i in range(modname._length_): + modname[i]='\x00' + + kernel.CloseHandle(hProcess) + +if __name__ == '__main__': + EnumProcesses() \ No newline at end of file Property changes on: pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py ___________________________________________________________________ Name: svn:eol-style + native Added: pymoul/trunk/src/moul/osdependent/win32/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/processinfo.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/win32/processinfo.py 2007-01-26 16:40:35 UTC (rev 84) @@ -0,0 +1,34 @@ +#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303339 +#Title: getting process information on windows +#Submitter: John Nielsen (other recipes) +#Last Updated: 2004/09/03 +#Version no: 1.0 +#Category: System + +import win32pdh, string, win32api + +def procids(): + #each instance is a process, you can have multiple processes w/same name + junk, instances = win32pdh.EnumObjectItems(None,None,'process', win32pdh.PERF_DETAIL_WIZARD) + proc_ids=[] + proc_dict={} + for instance in instances: + if instance in proc_dict: + proc_dict[instance] = proc_dict[instance] + 1 + else: + proc_dict[instance]=0 + for instance, max_instances in proc_dict.items(): + for inum in xrange(max_instances+1): + hq = win32pdh.OpenQuery() # initializes the query handle + path = win32pdh.MakeCounterPath( (None,'process',instance, None, inum,'ID Process') ) + counter_handle=win32pdh.AddCounter(hq, path) + win32pdh.CollectQueryData(hq) #collects data for the counter + type, val = win32pdh.GetFormattedCounterValue(counter_handle, win32pdh.PDH_FMT_LONG) + proc_ids.append((instance,str(val))) + win32pdh.CloseQuery(hq) + + proc_ids.sort() + return proc_ids + + +print procids() \ No newline at end of file Property changes on: pymoul/trunk/src/moul/osdependent/win32/processinfo.py ___________________________________________________________________ Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 16:29:25
|
Revision: 83 http://pymoul.svn.sourceforge.net/pymoul/?rev=83&view=rev Author: tiran Date: 2007-01-26 08:29:18 -0800 (Fri, 26 Jan 2007) Log Message: ----------- added test thread WMI is not thread safe :( Modified Paths: -------------- pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/moulqt.py Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 15:15:00 UTC (rev 82) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 16:29:18 UTC (rev 83) @@ -33,6 +33,7 @@ from moul.qt.ui.mainwindow import Ui_MainWindow from moul.qt.localization import LocalizationMixin +from moul.osdependent import isMoulRunning from moul.config import lookupDir from moul.file.wdysini import AudioIni from moul.file.wdysini import GraphicsIni @@ -45,6 +46,17 @@ LOG = getLogger('moul.qt') +def criticalMessageBox(self, title, text): + """Critical warning! + """ + mb = QtGui.QMessageBox() + mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) + mb.setIcon(QtGui.QMessageBox.Critical) + mb.setWindowTitle(self.trUtf8(title)) + mb.setText(self.trUtf8(text)) + mb.setStandardButtons(QtGui.QMessageBox.Close) + return mb + class MainWindow(QtGui.QMainWindow, Ui_MainWindow, LocalizationMixin): def __init__(self): QtGui.QMainWindow.__init__(self) @@ -69,7 +81,17 @@ self._systray_init() self.tab_documents.setEnabled(False) self._documents_init() + + # run checker + self._moulrunning_thread = MoulRunningThread() + self.connect(self._moulrunning_thread, SIGNAL('moulIsRunning(bool)'), + self.on_moulIsRunning) + self._moulrunning_thread.startChecker(10.0) # check now and every 10 seconds + @signalLogDecorator(LOG) + def on_moulIsRunning(self, bool): + pass + def _notimplemented(self): """TODO: remove me """ @@ -493,11 +515,13 @@ self._servers = None def pingServers(self, servers): + # TODO: thread safety! self.servers = servers if not self.isRunning(): self.start() def run(self): + # TODO: thread safety! self.emit(SIGNAL("started")) # emit a list of names first for server in self.servers: @@ -520,3 +544,39 @@ self.emit(SIGNAL("ping(const QString&, float)"), name, ping) self.emit(SIGNAL("done()")) + +class MoulRunningThread(QtCore.QThread): + def __init__(self, parent=None): + QtCore.QThread.__init__(self, parent) + self.mutex = QtCore.QMutex() + self.condition = QtCore.QWaitCondition() + self._timer = None + self._running = False + + def startChecker(self, timer): + self._timer = long(timer * 1000) + if not self.isRunning(): + self._running = True + self.start() + + def stopChecker(self): + # TODO check this + self._running = False + self.condition.wakeAll() + + def __del__(self): + self.stopChecker() + + def run(self): + while True: + result = True #isMoulRunning() + if result: + self.emit(SIGNAL('moulIsRunning(bool)'), True) + else: + self.emit(SIGNAL('moulIsRunning(bool)'), False) + + self.mutex.lock() + self.condition.wait(self.mutex, self._timer) + self.mutex.unlock() + if not self._running: + return Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 15:15:00 UTC (rev 82) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 16:29:18 UTC (rev 83) @@ -27,36 +27,28 @@ from PyQt4 import QtGui from moul.qt.mainwindow import MainWindow +from moul.qt.mainwindow import criticalMessageBox from moul.osdependent.singleapp import SimpleSingleApp from moul.config import getPyMoulDataDir from moul.osdependent import isMoulRunning -def critical(self, title, text): - """Critical warning! - """ - mb = QtGui.QMessageBox() - mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) - mb.setIcon(QtGui.QMessageBox.Critical) - mb.setWindowTitle(self.trUtf8(title)) - mb.setText(self.trUtf8(text)) - mb.setStandardButtons(QtGui.QMessageBox.Close) - return mb - def main(*args): app = QtGui.QApplication(*args) singleapp = SimpleSingleApp('pymoulqt', path=getPyMoulDataDir()) try: singleapp.acquire() except OSError: - mb = critical(app, "pyMoul QT already running", + mb = criticalMessageBox(app, + "pyMoul QT already running", """An instance of pyMoul QT is already running!""") mb.exec_() sys.exit(1) - if isMoulRunning(): - mb = critical(app, "URU is running", - """URU is running! Please close Uru or Uru Launcher first.""") - mb.exec_() - sys.exit(2) + #if isMoulRunning(): + # mb = criticalMessageBox(app, + # "URU is running", + # """URU is running! Please close Uru or Uru Launcher first.""") + # mb.exec_() + # sys.exit(2) mainWindow = MainWindow() mainWindow.show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 15:15:02
|
Revision: 82 http://pymoul.svn.sourceforge.net/pymoul/?rev=82&view=rev Author: tiran Date: 2007-01-26 07:15:00 -0800 (Fri, 26 Jan 2007) Log Message: ----------- Fixed exe build Check for isMoulRunning inside QT ui Modified Paths: -------------- pymoul/trunk/setup_win32.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/qt/moulqt.py Modified: pymoul/trunk/setup_win32.py =================================================================== --- pymoul/trunk/setup_win32.py 2007-01-26 14:55:52 UTC (rev 81) +++ pymoul/trunk/setup_win32.py 2007-01-26 15:15:00 UTC (rev 82) @@ -68,11 +68,12 @@ pexe = kw['options'].setdefault('py2exe', {}) pexe['compressed'] = 100 # compress zip file pexe['optimize'] = 0 # 0,1,2 - pexe['includes'] = ['sip', 'PyQt4', 'encodings', 'encodings.*'] + pexe['includes'] = ['sip', 'PyQt4', 'encodings', 'encodings.*', + 'moul.osdependent.win32', 'moul.osdependent.win32.*'] # SSL currently not in use but imported by socket pexe['excludes'] = ['_ssl'] # added by platform but not yet required - pexe['excludes'].extend(('win32pipe', 'win32api', 'win32con', 'win32evtlog')) + #pexe['excludes'].extend(('win32pipe', 'win32api', 'win32con', 'win32evtlog')) # added by logging.handlers.SMTPHandler but not yet required pexe['excludes'].append('smtplib') # UPX Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-26 14:55:52 UTC (rev 81) +++ pymoul/trunk/src/moul/log.py 2007-01-26 15:15:00 UTC (rev 82) @@ -113,12 +113,12 @@ #_systemInfo() else: _installMemoryHdlr() - # Redirect stdout and stderr to logger when running as frozen app - sys.stdout = LoggingStdout(getLogger('stdout').info) - sys.stderr = LoggingStdout(getLogger('stderr').error) _systemInfo() _installFileHdlr() _removeMemoryHdlr() + # Redirect stdout and stderr to logger when running as frozen app + #sys.stdout = LoggingStdout(getLogger('stdout').info) + #sys.stderr = LoggingStdout(getLogger('stderr').error) __LOG_SIGNALS__ = not __FROZEN__ def signalLogDecorator(__logger__): Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 14:55:52 UTC (rev 81) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 15:15:00 UTC (rev 82) @@ -35,7 +35,10 @@ import os import sys +from moul.log import getLogger +LOG = getLogger('moul.osdependent') + # a program under py2exe is sys.frozen __FROZEN__ = bool(getattr(sys, 'frozen', False)) # OS stuff Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 14:55:52 UTC (rev 81) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 15:15:00 UTC (rev 82) @@ -29,21 +29,34 @@ from moul.qt.mainwindow import MainWindow from moul.osdependent.singleapp import SimpleSingleApp from moul.config import getPyMoulDataDir +from moul.osdependent import isMoulRunning +def critical(self, title, text): + """Critical warning! + """ + mb = QtGui.QMessageBox() + mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) + mb.setIcon(QtGui.QMessageBox.Critical) + mb.setWindowTitle(self.trUtf8(title)) + mb.setText(self.trUtf8(text)) + mb.setStandardButtons(QtGui.QMessageBox.Close) + return mb + def main(*args): app = QtGui.QApplication(*args) singleapp = SimpleSingleApp('pymoulqt', path=getPyMoulDataDir()) try: singleapp.acquire() except OSError: - mb = QtGui.QMessageBox() - mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) - mb.setIcon(QtGui.QMessageBox.Critical) - mb.setWindowTitle(app.trUtf8("Already running")) - mb.setText(app.trUtf8("""An instance of pyMoul QT is already running!""")) - mb.setStandardButtons(QtGui.QMessageBox.Close) + mb = critical(app, "pyMoul QT already running", + """An instance of pyMoul QT is already running!""") mb.exec_() sys.exit(1) + if isMoulRunning(): + mb = critical(app, "URU is running", + """URU is running! Please close Uru or Uru Launcher first.""") + mb.exec_() + sys.exit(2) mainWindow = MainWindow() mainWindow.show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 14:55:56
|
Revision: 81 http://pymoul.svn.sourceforge.net/pymoul/?rev=81&view=rev Author: tiran Date: 2007-01-26 06:55:52 -0800 (Fri, 26 Jan 2007) Log Message: ----------- Added isMoulRunning stuff Enhanced startMoul Added some (disabled) tests for start and is running Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.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 Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/config/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -16,6 +16,30 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # """Configuration package + +>>> from moul.osdependent import startMoul +>>> from moul.osdependent import isMoulRunning +>>> installDir = lookupDir('install') +>>> from time import sleep + +Start MOUL +#>>> popen = startMoul(installDir) + +Wait a bit before testing the rest +#>>> sleep(0.2) +#>>> bool(popen.pid) +True +#>>> popen.poll() +#>>> popen.returncode is None +True + +Check the running tester +#>>> isMoulRunning() +u'urulauncher.exe' + +#>>> popen.wait() +#>>> popen.returncode +#0 """ import os Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -53,7 +53,7 @@ # names to import: from moul.osdependent.ID import NAME (as NAME) NAMES = ('getMoulUserDataDir', ('getPyMoulDataDir', '_getPyMoulDataDir'), # as - '_startMOUL', 'EXEC_NAME', + 'startMoul', 'isMoulRunning', 'getCurrentPids', 'getCurrentPidNames', ) Modified: pymoul/trunk/src/moul/osdependent/darwin/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -22,9 +22,12 @@ __revision__ = "$Revision$" import os -from moul.log import LOG -LOG.warning('Darwin/Mac support is not tested') +from subprocess import Popen +from moul.log import getLogger +LOG = getLogger('moul.darwin') +LOG.critical('Darwin/Mac support is not tested') + MOUL_DIR = "Uru Live" EXEC_NAME = "UruLauncher" HOME = os.environ['HOME'] @@ -43,12 +46,12 @@ inidir= os.path.join(HOME, '.pymoul') return inidir -def _startMOUL(installdir, *args): - """Start MOUL +def startMoul(installdir, *args, **kwargs): + """Start MOUL - returns a Popen instance + + args are applied to the program while kwargs are applied to + subprocess.Popen() """ - # P_DETACH is similar to P_NOWAIT, but the new process is detached from - # the console of the calling process. - mode = os.P_DETACH path = os.path.join(installdir, EXEC_NAME) - args = (EXEC_NAME,) + args - return os.spawnv(mode, path, args) + args = ' '.join(args) + return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -22,13 +22,17 @@ __revision__ = "$Revision$" import os -from moul.log import LOG -LOG.warning('Linux support is not tested') +from subprocess import Popen +from moul.log import getLogger +LOG = getLogger('moul.linux') +LOG.critical('Darwin/Mac support is not tested') + MOUL_DIR = "Uru Live" INI_FILE = ('pyMoul', 'pymoul.ini') EXEC_NAME = "UruLauncher" HOME = os.environ['HOME'] +PROCESSES = ('urulauncher', 'uruexplorer') def getMoulUserDataDir(): """Get path of MOUL data directory @@ -44,19 +48,26 @@ inidir= os.path.join(HOME, '.pymoul') return inidir -def _startMOUL(installdir, *args): - """Start MOUL +def startMoul(installdir, *args, **kwargs): + """Start MOUL - returns a Popen instance + + args are applied to the program while kwargs are applied to + subprocess.Popen() """ - # P_DETACH is similar to P_NOWAIT, but the new process is detached from - # the console of the calling process. - mode = os.P_DETACH path = os.path.join(installdir, EXEC_NAME) - args = (EXEC_NAME,) + args - return os.spawnv(mode, path, args) + args = ' '.join(args) + return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) +def isMoulRunning(): + """Test if MOUL or the launcher is running + """ + for pid, name in getCurrentPidNames().items(): + if name.lower() in PROCESSES: + return name.lower() + return False + # process info # based on http://gelb.bcom.at/trac/misc/browser/processinfo - def getCurrentPids(): """Returns current process ids """ Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -22,18 +22,25 @@ __revision__ = "$Revision$" import os +from subprocess import Popen + from moul.osdependent.win32.miniwinshell import my_documents as getMyDocuments from moul.osdependent.win32.miniwinshell import application_data as getAppdata #from moul.osdependent.win32.winpath import get_homedir as getMyDocuments #from moul.osdependent.win32.winpath import get_appdata as getAppdata from moul.osdependent.win32 import wmi +from moul.log import getLogger +LOG = getLogger('moul.win') + MOUL_DIR = "Uru Live" -EXEC_NAME = "UruLauncher.exe" +EXEC_NAME = "UruLauncher.exe" +# lower case +PROCESSES = ("urulauncher.exe", "uruexplorer.exe") -mycomputer = None -mydocs = getMyDocuments() -myappdata = getAppdata() +MYCOMPUTER = None # wmi instance +MYDOCS = getMyDocuments() +MYAPPDATA = getAppdata() def getMoulUserDataDir(): """Get path of MOUL data directory @@ -41,41 +48,48 @@ The MOUL data directory contains log files, chatlogs, KI images and many more things. """ - moul_data = os.path.join(mydocs, MOUL_DIR) + moul_data = os.path.join(MYDOCS, MOUL_DIR) return moul_data def getPyMoulDataDir(): """Get path to the pyMoul ini file """ - inidir = os.path.join(myappdata , 'pyMoul') + inidir = os.path.join(MYAPPDATA , 'pyMoul') return inidir -def _startMOUL(installdir, *args): - """Start MOUL +def startMoul(installdir, *args, **kwargs): + """Start MOUL - returns a Popen instance + + args are applied to the program while kwargs are applied to + subprocess.Popen() """ - # TODO: use subprocess module - # P_DETACH is similar to P_NOWAIT, but the new process is detached from - # the console of the calling process. - mode = os.P_DETACH path = os.path.join(installdir, EXEC_NAME) - args = (EXEC_NAME,) + args - return os.spawnv(mode, path, args) + args = ' '.join(args) + return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) +def isMoulRunning(): + """Test if MOUL or the launcher is running + """ + for pid, name in getCurrentPidNames().items(): + if name.lower() in PROCESSES: + return name.lower() + return False + def getCurrentPids(): """Returns mapping pid -> name """ - global mycomputer - if mycomputer is None: + global MYCOMPUTER + if MYCOMPUTER is None: # XXX: extremely slow, also see getCurrentPidNames - mycomputer = wmi.WMI() - return [process.ProcessId for process in mycomputer.Win32_Process()] + MYCOMPUTER = wmi.WMI() + return [process.ProcessId for process in MYCOMPUTER.Win32_Process()] def getCurrentPidNames(): """Returns mapping pid -> name """ - global mycomputer - if mycomputer is None: - mycomputer = wmi.WMI() + global MYCOMPUTER + if MYCOMPUTER is None: + MYCOMPUTER = wmi.WMI() return dict([(process.ProcessId, process.Name) - for process in mycomputer.Win32_Process() + for process in MYCOMPUTER.Win32_Process() ]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 14:17:52
|
Revision: 80 http://pymoul.svn.sourceforge.net/pymoul/?rev=80&view=rev Author: tiran Date: 2007-01-26 06:17:50 -0800 (Fri, 26 Jan 2007) Log Message: ----------- More cleanups Use WMI (f.... slow) to get process informations under Linux. Memo to me: put it inside a thread Moved os specific stuff around Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/osdependent/linux/__init__.py pymoul/trunk/src/moul/osdependent/processinfo.py pymoul/trunk/src/moul/osdependent/win32/__init__.py pymoul/trunk/src/moul/qt/ui/mainwindow.py Added Paths: ----------- pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py pymoul/trunk/src/moul/osdependent/win32/wmi.py Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/config/__init__.py 2007-01-26 14:17:50 UTC (rev 80) @@ -18,70 +18,13 @@ """Configuration package """ import os -import sys -from logging import getLogger -LOG = getLogger('pyMoul') +from moul.osdependent import getMoulUserDataDir +from moul.osdependent import getPyMoulDataDir -# a program under py2exe is sys.frozen -__FROZEN__ = bool(getattr(sys, 'frozen', False)) -# OS stuff -__WIN32__ = sys.platform.startswith('win32') # win64, cygwin? -__LINUX__ = sys.platform.startswith('linux2') -__MACOSX__ = sys.platform.startswith('darwin') -__UNIX__ = __LINUX__ or __MACOSX__ - -LOG.debug("sys.frozen status: %s" % __FROZEN__) -LOG.debug("OS detected: win32: %s, Linux: %s, Mac: %s, Un*x: %s" % - (__WIN32__, __LINUX__, __MACOSX__, __UNIX__)) - _marker=object() -# XXX: what about cygwin, bsd and others? -if __WIN32__: - from moul.osdependent.win32 import ( - getMoulUserDataDir, - getPyMoulDataDir as _getPyMoulDataDir, - _startMOUL, - EXEC_NAME - ) -elif __LINUX__: - from moul.osdependent.linux import ( - getMoulUserDataDir, - getPyMoulDataDir as _getPyMoulDataDir, - _startMOUL, - EXEC_NAME - ) -elif __MACOSX__: - from moul.osdependent.darwin import ( - getMoulUserDataDir, - getPyMoulDataDir as _getPyMoulDataDir, - _startMOUL, - EXEC_NAME - ) -else: - raise RuntimeError('platform %s not supported' % sys.platform) -def getPyMoulDataDir(check=False): - """Get pyMoul data directory - - The directory contains log files, ini files and other local stuff - """ - datadir = _getPyMoulDataDir() - if check: - if os.path.abspath(datadir) != datadir: - raise ValueError("Datadir is not absolute %s" % datadir) - if not os.path.isdir(datadir): - parent = os.path.abspath(os.path.join(datadir, os.pardir)) - if not os.path.isdir(parent): - raise ValueError("Datadir's parent dir does not exist: %s" - % par) - else: - LOG.debug("Creating pyMoul data dir %s" % datadir) - os.mkdir(datadir, 0750) - LOG.debug("Using pyMoul data dir %s" % datadir) - return datadir - -## configuration +# configuration class Configuration(dict): def __new__(cls, *args, **kwargs): self = dict.__new__(cls, *args, **kwargs) Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/log.py 2007-01-26 14:17:50 UTC (rev 80) @@ -33,9 +33,7 @@ getLogger = logging.getLogger -# copied from moul.config to prevent circular imports __FROZEN__ = bool(getattr(sys, 'frozen', False)) -__LOG_SIGNALS__ = not __FROZEN__ format = Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', #'%a, %d %b %Y %H:%M:%S' @@ -92,6 +90,7 @@ fhdlr.doRollover() def _systemInfo(): + from moul.osdependent import __INFO__ LOG.debug("pyMoul version: %s" % moul_version) LOG.debug("Python: %s" % repr(sys.version_info)) LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) @@ -99,6 +98,9 @@ LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" % platform.uname()) LOG.debug("platform name: %s" % platform.platform(True)) + LOG.debug("sys.frozen status: %s" % __FROZEN__) + LOG.debug("OS detected: win32: %r, cygwin: %r, Linux: %r, Mac: %r, BSD: %r, " + "posix/Un*x: %r, NT: %r" % __INFO__) # no setup the logging stuff! @@ -108,6 +110,7 @@ shdlr = logging.StreamHandler(sys.stderr) shdlr.setFormatter(format) root.addHandler(shdlr) + #_systemInfo() else: _installMemoryHdlr() # Redirect stdout and stderr to logger when running as frozen app @@ -117,6 +120,7 @@ _installFileHdlr() _removeMemoryHdlr() +__LOG_SIGNALS__ = not __FROZEN__ def signalLogDecorator(__logger__): """Decorator to log signals Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 14:17:50 UTC (rev 80) @@ -15,8 +15,118 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # Temple Place, Suite 330, Boston, MA 02111-1307 USA # +"""OS dependent code for linux, mac and win32 + +>>> pids = getCurrentPids() +>>> len(pids) > 1 +True + +>>> pids = getCurrentPidNames() +>>> found = False +>>> for pid, name in pids.items(): +... if name.lower().startswith('python'): +... found = True +>>> found +True """ -""" __author__ = "Christian Heimes" __version__ = "$Id$" __revision__ = "$Revision$" + +import os +import sys + +# a program under py2exe is sys.frozen +__FROZEN__ = bool(getattr(sys, 'frozen', False)) +# OS stuff +_plat = sys.platform.startswith +__WIN32__ = _plat('win32') # win64, cygwin? +__CYGWIN__ = _plat('cygwin') +__LINUX__ = _plat('linux2') +__MACOSX__ = _plat('darwin') +__BSD__ = _plat('freebsd') or _plat('netbsd') or _plat('openbsd') +__POSIX__ = os.name.lower() == 'posix' +__NT__ = os.name.lower() == 'nt' +__INFO__ = (__WIN32__, __CYGWIN__, __LINUX__, __MACOSX__, __BSD__, + __POSIX__, __NT__) + +# names to import: from moul.osdependent.ID import NAME (as NAME) +NAMES = ('getMoulUserDataDir', + ('getPyMoulDataDir', '_getPyMoulDataDir'), # as + '_startMOUL', 'EXEC_NAME', + 'getCurrentPids', 'getCurrentPidNames', + ) + +_marker = object() + +def _importHelper(modname, names=None, target=None): + """Import a list of variables from a module + + >>> mod = _importHelper('moul.osdependent') + >>> mod == _thismodule or mod + True + >>> vars = _importHelper('moul.osdependent', ('_marker', )) + >>> vars[0] is _marker + True + >>> class Target(object): + ... pass + >>> target = Target() + >>> vars = _importHelper('moul.osdependent', ('_marker', ), target=target) + >>> target._marker is _marker + True + >>> vars[0] is _marker + True + + >>> vars = _importHelper('moul.osdependent', (('_marker', 'another'), ), + ... target=target) + >>> target.another is _marker + True + >>> vars[0] is _marker + True + """ + mod = __import__(modname, globals(), locals(), ['']) + if names is None: + return mod + else: + vars = [] + for name in names: + if isinstance(name, (tuple, list)): + name, nameas = name + else: + nameas = name + var = getattr(mod, name) + vars.append(var) + if target is not None: + setattr(target, nameas, var) + return vars + +# XXX: what about cygwin, bsd and others? +_thismodule = sys.modules[__name__] +if __WIN32__: + _importHelper('moul.osdependent.win32', NAMES, target=_thismodule) +elif __LINUX__: + _importHelper('moul.osdependent.linux', NAMES, target=_thismodule) +elif __MACOSX__: + _importHelper('moul.osdependent.darwin', NAMES, target=_thismodule) +else: + raise RuntimeError('platform %s not supported' % sys.platform) + +def getPyMoulDataDir(check=False): + """Get pyMoul data directory + + The directory contains log files, ini files and other local stuff + """ + datadir = _getPyMoulDataDir() + if check: + if os.path.abspath(datadir) != datadir: + raise ValueError("Datadir is not absolute %s" % datadir) + if not os.path.isdir(datadir): + parent = os.path.abspath(os.path.join(datadir, os.pardir)) + if not os.path.isdir(parent): + raise ValueError("Datadir's parent dir does not exist: %s" + % par) + else: + LOG.debug("Creating pyMoul data dir %s" % datadir) + os.mkdir(datadir, 0750) + LOG.debug("Using pyMoul data dir %s" % datadir) + return datadir Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-26 14:17:50 UTC (rev 80) @@ -53,3 +53,52 @@ path = os.path.join(installdir, EXEC_NAME) args = (EXEC_NAME,) + args return os.spawnv(mode, path, args) + +# process info +# based on http://gelb.bcom.at/trac/misc/browser/processinfo + +def getCurrentPids(): + """Returns current process ids + """ + pids = [] + for fname in os.listdir("/proc"): + if os.path.isdir(os.path.join("/proc", fname)): + try: + pids.append(int(fname)) + except ValueError: + continue + return pids + +def getCurrentPidDetails(): + """Returns mapping pid -> detailed informations + """ + mapping = {} + for pid in getCurrentPids(): + try: + try: + # read entiry file to avoid race condition bugs + fd = open('/proc/%i/status' % pid, 'rb') + status = fd.read().split('\n') + finally: + if fd: + fd.close() + except IoError: + continue + details = {} + for line in status: + try: + key, value = line.split(':\t') + except ValueError: + continue + details[key.lower()] = value.strip() + mapping[pid] = details + + return mapping + +def getCurrentPidNames(): + """Returns mapping pid -> name + """ + mapping = {} + for pid, details in getCurrentPidDetails().items(): + mapping[pid] = details.get('name', None) + return mapping Modified: pymoul/trunk/src/moul/osdependent/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/processinfo.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/osdependent/processinfo.py 2007-01-26 14:17:50 UTC (rev 80) @@ -1,219 +1,219 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-1 -*- -"""Process info - -Based on http://gelb.bcom.at/trac/misc/browser/processinfo - -Modified and optimized by Christian Heimes -""" - -import sys -import os - -__all__ = ['PLATFORM', 'UnsupportedOsError', 'getCurrentPids', - 'getCurrentPidNames', 'getCurrentPidDetails'] - -class UnsupportedOsError(NotImplementedError): - pass - -PLATFORM = None - -_plat = sys.platform.startswith -if _plat('win'): - PLATFORM = 'win' - win32process = None - ctypes = None - import csv - try: - import win32process - except ImportError: - try: - import ctypes - except ImportError: - pass -elif _plat('linux2') or _plat('cygwin'): - PLATFORM = 'linux' # Linux or Cygwin -elif _plat('darwin'): - # XXX: unsupported - PLATFORM = 'mac' # Mac OS X -elif _plat('freebsd') or _plat('netbsd') or _plat('openbsd'): - # XXX: unsupported - PLATFORM = 'bsd' # *BSD -else: - PLATFORM = 'unknown' - raise UnsupportedOsError(sys.platform) - -# **************************************************************************** -# Linux / cygwin implementation - -def _getCurrentPids_linux(): - """ - Returns current process-id's. - - :return: list with process-id's. - """ - pids = [] - for fname in os.listdir("/proc"): - if os.path.isdir(os.path.join("/proc", fname)): - try: - pids.append(int(fname)) - except ValueError: - continue - return pids - -def _getCurrentPidDetails_linux(): - """Returns mapping pid -> detailed informations - """ - mapping = {} - for pid in getCurrentPids(): - try: - try: - # read entiry file to avoid race condition bugs - fd = open('/proc/%i/status' % pid, 'rb') - status = fd.read().split('\n') - finally: - if fd: - fd.close() - except IoError: - continue - details = {} - for line in status: - try: - key, value = line.split(':\t') - except ValueError: - continue - details[key.lower()] = value.strip() - mapping[pid] = details - - return mapping - -# **************************************************************************** -# Windows / win32 implementaton - -def _getCurrentPids_win(): - """ - Returns current process-id's. - - :return: List with process-id's. - """ - if win32process is not None: - return list(win32process.EnumProcesses()) - elif ctypes is not None: - # ctypes is installed --> try psapi.dll - psapi = ct.windll.psapi - arr = ct.c_long * 1024 - process_ids = arr() - cb = ct.sizeof(process_ids) - bytes_returned = ct.c_ulong() - psapi.EnumProcesses(ct.byref(process_ids), cb, ct.byref(bytes_returned)) - return sorted(list(set(process_ids))) - else: - csvlines = [] - current_pids = [] - for line in os.popen("tasklist.exe /fo csv /nh"): - line = line.strip() - if line: - csvlines.append(line) - for line in csv.reader(csvlines): - current_pids.append(int(line[1])) - if not csvlines: - raise NotImplementedError("tasklist.exe not found (>WinXP)") - return current_pids - - -def _getCurrentPidDetails_win(): - """ - Returns processinfos. (pid, name and size_kb) - - On Windows-Systems, it uses ``tasklist.exe`` or WMI to list the processes. - On other platforms, it reads the "/proc"-directory. - - :return: Dictionary with PID's as keys and the infos as values in an - inner dictionary. (It is possible, that "size_kb" doesn't exist.): - { - 123: {"name": "bash", "pid": 123}, - 234: {"name": "mc", "pid": 234, "size_kb": 1000}, - } - """ - - retdict = {} - - # tasklist.exe runs on Windows XP and higher. (To parse the ouput of - # tasklist.exe is faster than WMI.) - import csv - csvlines = [] - for line in os.popen("tasklist.exe /fo csv /nh"): - line = line.strip() - if line: - csvlines.append(line) - for line in csv.reader(csvlines): - pid = int(line[1]) - details = { - "name": line[0].decode("cp850"), # to unicode - "pid": pid, - } - value = "".join( - char for char in line[4] - if char.isdigit() - ) - details["size_kb"] = int(value) - retdict[pid] = details - if not csvlines: - try: - from win32com.client import GetObject - # pywin32 is installed --> use WMI - wmi = GetObject('winmgmts:') - processes = wmi.InstancesOf('Win32_Process') - for process in processes: - pid = int(process.Properties_("ProcessId").value) - details = { - "name": process.Properties_("Name").value, - "pid": pid, - "size_kb": int(process.Properties_("WorkingSetSize").value) / 1000 - } - retdict[pid] = details - except ImportError: - raise NotImplementedError("No tasklist.exe and no WMI.") - return retdict - -# **************************************************************************** -# general - -def unsupported(): - """Platform not supported - """ - raise UnsupportedOsError(PLATFORM) - -def getCurrentPidNames(): - """Returns mapping pid -> name - """ - mapping = {} - for pid, details in getCurrentPidDetails().items(): - mapping[pid] = details.get('name', None) - return mapping - -def _initialize(): - mod = sys.modules[__name__] - for name in ('getCurrentPids','getCurrentPidDetails'): - func = getattr(mod, "_%s_%s" % (name, PLATFORM), unsupported) - #func.__name__ = name - setattr(mod, name, func) -_initialize() - -def main(): - """Testing""" - - from pprint import pformat - # Current PIDs - current_pids = getCurrentPids() - print "Current PIDs: %s" % pformat(current_pids) - print - print "Current PID Count: %s" % len(current_pids) - print - - print "Current PIDs with names: %s" % pformat(getCurrentPidNames()) - print - -if __name__ == "__main__": - main() - +#!/usr/bin/env python +# -*- coding: iso-8859-1 -*- +"""Process info + +Based on http://gelb.bcom.at/trac/misc/browser/processinfo + +Modified and optimized by Christian Heimes +""" + +import sys +import os + +__all__ = ['PLATFORM', 'UnsupportedOsError', 'getCurrentPids', + 'getCurrentPidNames', 'getCurrentPidDetails'] + +class UnsupportedOsError(NotImplementedError): + pass + +PLATFORM = None + +_plat = sys.platform.startswith +if _plat('win'): + PLATFORM = 'win' + win32process = None + ctypes = None + import csv + try: + import win32process + except ImportError: + try: + import ctypes + except ImportError: + pass +elif _plat('linux2') or _plat('cygwin'): + PLATFORM = 'linux' # Linux or Cygwin +elif _plat('darwin'): + # XXX: unsupported + PLATFORM = 'mac' # Mac OS X +elif _plat('freebsd') or _plat('netbsd') or _plat('openbsd'): + # XXX: unsupported + PLATFORM = 'bsd' # *BSD +else: + PLATFORM = 'unknown' + raise UnsupportedOsError(sys.platform) + +# **************************************************************************** +# Linux / cygwin implementation + +def _getCurrentPids_linux(): + """ + Returns current process-id's. + + :return: list with process-id's. + """ + pids = [] + for fname in os.listdir("/proc"): + if os.path.isdir(os.path.join("/proc", fname)): + try: + pids.append(int(fname)) + except ValueError: + continue + return pids + +def _getCurrentPidDetails_linux(): + """Returns mapping pid -> detailed informations + """ + mapping = {} + for pid in getCurrentPids(): + try: + try: + # read entiry file to avoid race condition bugs + fd = open('/proc/%i/status' % pid, 'rb') + status = fd.read().split('\n') + finally: + if fd: + fd.close() + except IoError: + continue + details = {} + for line in status: + try: + key, value = line.split(':\t') + except ValueError: + continue + details[key.lower()] = value.strip() + mapping[pid] = details + + return mapping + +def _getCurrentPidNames_linux(): + """Returns mapping pid -> name + """ + mapping = {} + for pid, details in getCurrentPidDetails().items(): + mapping[pid] = details.get('name', None) + return mapping + + +# **************************************************************************** +# Windows / win32 implementaton + +def _getCurrentPids_win(): + """ + Returns current process-id's. + + :return: List with process-id's. + """ + if win32process is not None: + return list(win32process.EnumProcesses()) + elif ctypes is not None: + # ctypes is installed --> try psapi.dll + psapi = ct.windll.psapi + arr = ct.c_long * 1024 + process_ids = arr() + cb = ct.sizeof(process_ids) + bytes_returned = ct.c_ulong() + psapi.EnumProcesses(ct.byref(process_ids), cb, ct.byref(bytes_returned)) + return sorted(list(set(process_ids))) + else: + csvlines = [] + current_pids = [] + for line in os.popen("tasklist.exe /fo csv /nh"): + line = line.strip() + if line: + csvlines.append(line) + for line in csv.reader(csvlines): + current_pids.append(int(line[1])) + if not csvlines: + raise NotImplementedError("tasklist.exe not found (>WinXP)") + return current_pids + +def _getCurrentPidNames_win(): + """Returns mapping pid -> name + """ + mapping = {} + for pid, details in getCurrentPidDetails().items(): + mapping[pid] = details.get('name', None) + return mapping + +def _getCurrentPidDetails_win(): + """ + Returns processinfos. (pid, name and size_kb) + """ + result = {} + + # tasklist.exe runs on Windows XP and higher. (To parse the ouput of + # tasklist.exe is faster than WMI.) + csvlines = [] + for line in os.popen("tasklist.exe /fo csv /nh"): + line = line.strip() + if line: + csvlines.append(line) + for line in csv.reader(csvlines): + pid = int(line[1]) + details = { + "name": line[0].decode("cp850"), # to unicode + "pid": pid, + } + value = "".join( + char for char in line[4] + if char.isdigit() + ) + details["size_kb"] = int(value) + retdict[pid] = details + if not csvlines: + try: + from win32com.client import GetObject + # pywin32 is installed --> use WMI + wmi = GetObject('winmgmts:') + processes = wmi.InstancesOf('Win32_Process') + for process in processes: + pid = int(process.Properties_("ProcessId").value) + details = { + "name": process.Properties_("Name").value, + "pid": pid, + "size_kb": int(process.Properties_("WorkingSetSize").value) / 1000 + } + retdict[pid] = details + except ImportError: + raise NotImplementedError("No tasklist.exe and no WMI.") + return retdict + +# **************************************************************************** +# general + +def unsupported(): + """Platform not supported + """ + raise UnsupportedOsError(PLATFORM) +unsupported.__unsupported__ = True + +def _initialize(): + mod = sys.modules[__name__] + for name in ('getCurrentPids','getCurrentPidDetails', 'getCurrentPidNames'): + func = getattr(mod, "_%s_%s" % (name, PLATFORM), None) + if func is None: + func = unsupported + else: + func.__name__ = name + setattr(mod, name, func) +_initialize() + +def main(): + """Testing""" + + from pprint import pformat + # Current PIDs + current_pids = getCurrentPids() + print "Current PIDs: %s" % pformat(current_pids) + print + print "Current PID Count: %s" % len(current_pids) + print + + print "Current PIDs with names: %s" % pformat(getCurrentPidNames()) + print + +if __name__ == "__main__": + main() + Added: pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py =================================================================== --- pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py 2007-01-26 14:17:50 UTC (rev 80) @@ -0,0 +1,36 @@ +# 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 +# +"""moul.osdependent.singleapp +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import unittest +from doctest import DocTestSuite + +import moul.osdependent + +def test_suite(): + return unittest.TestSuite(( + DocTestSuite('moul.osdependent'), + )) + +if __name__ == '__main__': + unittest.main(defaultTest="test_suite") + Property changes on: pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py ___________________________________________________________________ Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 14:17:50 UTC (rev 80) @@ -22,29 +22,32 @@ __revision__ = "$Revision$" import os -#from moul.osdependent.win32.miniwinshell import my_documents -#from moul.osdependent.win32.miniwinshell import application_data -from moul.osdependent.win32.winpath import get_homedir -from moul.osdependent.win32.winpath import get_appdata +from moul.osdependent.win32.miniwinshell import my_documents as getMyDocuments +from moul.osdependent.win32.miniwinshell import application_data as getAppdata +#from moul.osdependent.win32.winpath import get_homedir as getMyDocuments +#from moul.osdependent.win32.winpath import get_appdata as getAppdata +from moul.osdependent.win32 import wmi MOUL_DIR = "Uru Live" EXEC_NAME = "UruLauncher.exe" +mycomputer = None +mydocs = getMyDocuments() +myappdata = getAppdata() + def getMoulUserDataDir(): """Get path of MOUL data directory The MOUL data directory contains log files, chatlogs, KI images and many more things. """ - mydoc = get_homedir() - moul_data = os.path.join(mydoc, MOUL_DIR) + moul_data = os.path.join(mydocs, MOUL_DIR) return moul_data def getPyMoulDataDir(): """Get path to the pyMoul ini file """ - app_data = get_appdata() - inidir = os.path.join(app_data, 'pyMoul') + inidir = os.path.join(myappdata , 'pyMoul') return inidir def _startMOUL(installdir, *args): @@ -57,3 +60,22 @@ path = os.path.join(installdir, EXEC_NAME) args = (EXEC_NAME,) + args return os.spawnv(mode, path, args) + +def getCurrentPids(): + """Returns mapping pid -> name + """ + global mycomputer + if mycomputer is None: + # XXX: extremely slow, also see getCurrentPidNames + mycomputer = wmi.WMI() + return [process.ProcessId for process in mycomputer.Win32_Process()] + +def getCurrentPidNames(): + """Returns mapping pid -> name + """ + global mycomputer + if mycomputer is None: + mycomputer = wmi.WMI() + return dict([(process.ProcessId, process.Name) + for process in mycomputer.Win32_Process() + ]) Added: pymoul/trunk/src/moul/osdependent/win32/wmi.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/wmi.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/win32/wmi.py 2007-01-26 14:17:50 UTC (rev 80) @@ -0,0 +1,1246 @@ +## +# wmi - a lightweight Python wrapper around Microsoft's WMI interface +# +# Windows Management Instrumentation (WMI) is Microsoft's answer to +# the DMTF's Common Information Model. It allows you to query just +# about any conceivable piece of information from any computer which +# is running the necessary agent and over which have you the +# necessary authority. +# +# The implementation is by means of COM/DCOM and most of the examples +# assume you're running one of Microsoft's scripting technologies. +# Fortunately, Mark Hammond's pywin32 has pretty much all you need +# for a workable Python adaptation. I haven't tried any of the fancier +# stuff like Async calls and so on, so I don't know if they'd work. +# +# Since the COM implementation doesn't give much away to Python +# programmers, I've wrapped it in some lightweight classes with +# some getattr / setattr magic to ease the way. In particular: +# +# <ul> +# <li> +# The _wmi_namespace object itself will determine its classes +# and allow you to return all instances of any of them by +# using its name as an attribute. As an additional shortcut, +# you needn't specify the Win32_; if the first lookup fails +# it will try again with a Win32_ on the front: +# +# <pre class="code"> +# disks = wmi.WMI ().Win32_LogicalDisk () +# </pre> +# +# In addition, you can specify what would become the WHERE clause +# as keyword parameters: +# +# <pre class="code"> +# fixed_disks = wmi.WMI ().Win32_LogicalDisk (DriveType = 3) +# </pre> +# </li> +# +# <li> +# The objects returned by a WMI lookup are wrapped in a Python +# class which determines their methods and classes and allows +# you to access them as though they were Python classes. The +# methods only allow named parameters. +# +# <pre class="code"> +# for p in wmi.WMI ().Win32_Process (): +# if p.Name.lower () == 'notepad.exe': +# p.Terminate (Result=1) +# </pre> +# </li> +# +# <li> +# Doing a print on one of the WMI objects will result in its +# GetObjectText_ method being called, which usually produces +# a meaningful printout of current values. +# The repr of the object will include its full WMI path, +# which lets you get directly to it if you need to. +# </li> +# +# <li> +# You can get the associators and references of an object as +# a list of python objects by calling the associators () and +# references () methods on a WMI Python object. +# NB Don't do this on a Win32_ComputerSystem object; it will +# take all day and kill your machine! +# +# <pre class="code"> +# for p in wmi.WMI ().Win32_Process (): +# if p.Name.lower () == 'notepad.exe': +# for r in p.references (): +# print r.Name +# </pre> +# </li> +# +# <li> +# WMI classes (as opposed to instances) are first-class +# objects, so you can get hold of a class, and call +# its methods or set up a watch against it. +# +# <pre class="code"> +# process = wmi.WMI ().Win32_Process +# process.Create (CommandLine="notepad.exe") +# </pre> +# +# </li> +# +# <li> +# To make it easier to use in embedded systems and py2exe-style +# executable wrappers, the module will not force early Dispatch. +# To do this, it uses a handy hack by Thomas Heller for easy access +# to constants. +# </li> +# +# <li> +# Typical usage will be: +# +# <pre class="code"> +# import wmi +# +# vodev1 = wmi.WMI ("vodev1") +# for disk in vodev1.Win32_LogicalDisk (): +# if disk.DriveType == 3: +# space = 100 * long (disk.FreeSpace) / long (disk.Size) +# print "%s has %d%% free" % (disk.Name, space) +# </pre> +# </li> +# +# </ul> +# +# Many thanks, obviously to Mark Hammond for creating the win32all +# extensions, but also to Alex Martelli and Roger Upole, whose +# c.l.py postings pointed me in the right direction. +# Thanks especially in release 1.2 to Paul Tiemann for his code +# contributions and robust testing. +# +# (c) Tim Golden - mail at timgolden.me.uk 5th June 2003 +# Licensed under the (GPL-compatible) MIT License: +# http://www.opensource.org/licenses/mit-license.php +# +# For change history see CHANGELOG.TXT +## +try: + True, False +except NameError: + True = 1 + False = 0 + +try: + object +except NameError: + class object: pass + +__VERSION__ = "1.2.1" + +_DEBUG = False + +import sys +import re +from win32com.client import GetObject, Dispatch +import pywintypes + +class ProvideConstants (object): + """ + A class which, when called on a win32com.client.Dispatch object, + provides lazy access to constants defined in the typelib. + + They can be accessed as attributes of the _constants property. + From Thomas Heller on c.l.py + """ + def __init__(self, comobj): + "@param comobj A COM object whose typelib constants are to be exposed" + comobj.__dict__["_constants"] = self + # Get the typelibrary's typecomp interface + self.__typecomp = \ + comobj._oleobj_.GetTypeInfo().GetContainingTypeLib()[0].GetTypeComp() + + def __getattr__(self, name): + if name.startswith("__") and name.endswith("__"): + raise AttributeError, name + result = self.__typecomp.Bind(name) + # Bind returns a 2-tuple, first item is TYPEKIND, + # the second item has the value + if not result[0]: + raise AttributeError, name + return result[1].value + +obj = GetObject ("winmgmts:") +ProvideConstants (obj) + +wbemErrInvalidQuery = obj._constants.wbemErrInvalidQuery +wbemErrTimedout = obj._constants.wbemErrTimedout +wbemFlagReturnImmediately = obj._constants.wbemFlagReturnImmediately +wbemFlagForwardOnly = obj._constants.wbemFlagForwardOnly + +def handle_com_error (error_info): + """Convenience wrapper for displaying all manner of COM errors. + Raises a x_wmi exception with more useful information attached + + @param error_info The structure attached to a pywintypes.com_error + """ + hresult_code, hresult_name, additional_info, parameter_in_error = error_info + exception_string = ["%s - %s" % (hex (hresult_code), hresult_name)] + if additional_info: + wcode, source_of_error, error_description, whlp_file, whlp_context, scode = additional_info + exception_string.append (" Error in: %s" % source_of_error) + exception_string.append (" %s - %s" % (hex (scode), error_description.strip ())) + raise x_wmi, "\n".join (exception_string) + +def from_time (year=None, month=None, day=None, hours=None, minutes=None, seconds=None, microseconds=None, timezone=None): + """ + Convenience wrapper to take a series of date/time elements and return a WMI time + of the form yyyymmddHHMMSS.mmmmmm+UUU. All elements may be int, string or + omitted altogether. If omitted, they will be replaced in the output string + by a series of stars of the appropriate length. + + @param year The year element of the date/time + @param month The month element of the date/time + @param day The day element of the date/time + @param hours The hours element of the date/time + @param minutes The minutes element of the date/time + @param seconds The seconds element of the date/time + @param microseconds The microseconds element of the date/time + @param timezone The timeezone element of the date/time + + @return A WMI datetime string of the form: yyyymmddHHMMSS.mmmmmm+UUU + """ + def str_or_stars (i, length): + if i is None: + return "*" * length + else: + return str (i).rjust (length, "0") + + wmi_time = "" + wmi_time += str_or_stars (year, 4) + wmi_time += str_or_stars (month, 2) + wmi_time += str_or_stars (day, 2) + wmi_time += str_or_stars (hours, 2) + wmi_time += str_or_stars (minutes, 2) + wmi_time += str_or_stars (seconds, 2) + wmi_time += "." + wmi_time += str_or_stars (microseconds, 6) + wmi_time += str_or_stars (timezone, 4) + + return wmi_time + +def to_time (wmi_time): + """ + Convenience wrapper to take a WMI datetime string of the form + yyyymmddHHMMSS.mmmmmm+UUU and return a 9-tuple containing the + individual elements, or None where string contains placeholder + stars. + + @param wmi_time The WMI datetime string in yyyymmddHHMMSS.mmmmmm+UUU format + + @return A 9-tuple of (year, month, day, hours, minutes, seconds, microseconds, timezone) + """ + def int_or_none (s, start, end): + try: + return int (s[start:end]) + except ValueError: + return None + + year = int_or_none (wmi_time, 0, 4) + month = int_or_none (wmi_time, 4, 6) + day = int_or_none (wmi_time, 6, 8) + hours = int_or_none (wmi_time, 8, 10) + minutes = int_or_none (wmi_time, 10, 12) + seconds = int_or_none (wmi_time, 12, 14) + microseconds = int_or_none (wmi_time, 15, 21) + timezone = wmi_time[21:] + + return year, month, day, hours, minutes, seconds, microseconds, timezone + +# +# Exceptions +# +class x_wmi (Exception): + pass + +class x_wmi_invalid_query (x_wmi): + pass + +class x_wmi_timed_out (x_wmi): + pass + +class x_wmi_no_namespace (x_wmi): + pass + +WMI_EXCEPTIONS = { + wbemErrInvalidQuery : x_wmi_invalid_query, + wbemErrTimedout : x_wmi_timed_out +} + +def _set (obj, attribute, value): + """ + Helper function to add an attribute directly into the instance + dictionary, bypassing possible __getattr__ calls + + @param obj Any python object + @param attribute String containing attribute name + @param value Any python object + """ + obj.__dict__[attribute] = value + +class _wmi_method: + """ + A currying sort of wrapper around a WMI method name. It + abstract's the method's parameters and can be called like + a normal Python object passing in the parameter values. + + Output parameters are returned from the call as a tuple. + In addition, the docstring is set up as the method's + signature, including an indication as to whether any + given parameter is expecting an array, and what + special privileges are required to call the method. + """ + + def __init__ (self, ole_object, method_name): + """ + @param ole_object The WMI class/instance whose method is to be called + @param method_name The name of the method to be called + """ + try: + self.ole_object = Dispatch (ole_object) + self.method = ole_object.Methods_ (method_name) + self.qualifiers = {} + for q in self.method.Qualifiers_: + self.qualifiers[q.Name] = q.Value + self.provenance = "\n".join (self.qualifiers.get ("MappingStrings", [])) + + self.in_parameters = self.method.InParameters + self.out_parameters = self.method.OutParameters + if self.in_parameters is None: + self.in_parameter_names = [] + else: + self.in_parameter_names = [(i.Name, i.IsArray) for i in self.in_parameters.Properties_] + if self.out_parameters is None: + self.out_parameter_names = [] + else: + self.out_parameter_names = [(i.Name, i.IsArray) for i in self.out_parameters.Properties_] + + doc = "%s (%s) => (%s)" % ( + method_name, + ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.in_parameter_names]), + ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.out_parameter_names]) + ) + privileges = self.qualifiers.get ("Privileges", []) + if privileges: + doc += " | Needs: " + ", ".join (privileges) + self.__doc__ = doc + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __call__ (self, **kwargs): + """ + Execute the call to a WMI method, returning + a tuple (even if is of only one value) containing + the out and return parameters. + """ + try: + if self.in_parameters: + parameter_names = {} + for name, is_array in self.in_parameter_names: + parameter_names[name] = is_array + + parameters = self.in_parameters + for k, v in kwargs.items (): + is_array = parameter_names.get (k) + if is_array is None: + raise AttributeError, "%s is not a valid parameter for %s" % (k, self.__doc__) + else: + if is_array: + try: list (v) + except TypeError: raise TypeError, "%s must be iterable" % k + + parameters.Properties_ (k).Value = v + + result = self.ole_object.ExecMethod_ (self.method.Name, self.in_parameters) + else: + result = self.ole_object.ExecMethod_ (self.method.Name) + + results = [] + for name, is_array in self.out_parameter_names: + value = result.Properties_ (name).Value + if is_array: + # + # Thanks to Jonas Bjering for bug report and path + # + results.append (list (value or [])) + else: + results.append (value) + return tuple (results) + + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __repr__ (self): + return "<function %s>" % self.__doc__ + +# +# class _wmi_object +# +class _wmi_object: + "A lightweight wrapper round an OLE WMI object" + + def __init__ (self, ole_object, instance_of=None, fields=[]): + try: + _set (self, "ole_object", ole_object) + _set (self, "_instance_of", instance_of) + _set (self, "properties", {}) + _set (self, "methods", {}) + + if self._instance_of: + if fields: + for field in fields: + self.properties[field] = None + else: + _set (self, "properties", self._instance_of.properties.copy ()) + _set (self, "methods", self._instance_of.methods) + else: + for p in ole_object.Properties_: + self.properties[p.Name] = None + for m in ole_object.Methods_: + self.methods[m.Name] = None + + _set (self, "_properties", self.properties.keys ()) + _set (self, "_methods", self.methods.keys ()) + + _set (self, "qualifiers", {}) + for q in self.ole_object.Qualifiers_: + self.qualifiers[q.Name] = q.Value + _set (self, "is_association", self.qualifiers.has_key ("Association")) + + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __str__ (self): + """ + For a call to print [object] return the OLE description + of the properties / values of the object + """ + try: + return self.ole_object.GetObjectText_ () + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __repr__ (self): + """ + Indicate both the fact that this is a wrapped WMI object + and the WMI object's own identifying class. + """ + try: + return "<%s: %s>" % (self.__class__.__name__, str (self.Path_.Path)) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def _cached_properties (self, attribute): + if self.properties[attribute] is None: + self.properties[attribute] = self.ole_object.Properties_ (attribute) + return self.properties[attribute] + + def _cached_methods (self, attribute): + if self.methods[attribute] is None: + self.methods[attribute] = _wmi_method (self.ole_object, attribute) + return self.methods[attribute] + + def __getattr__ (self, attribute): + """ + Attempt to pass attribute calls to the proxied COM object. + If the attribute is recognised as a property, return its value; + if it is recognised as a method, return a method wrapper which + can then be called with parameters; otherwise pass the lookup + on to the underlying object. + """ + try: + if self.properties.has_key (attribute): + value = self._cached_properties (attribute).Value + # + # If this is an association, its properties are + # actually the paths to the two aspects of the + # association, so translate them automatically + # into WMI objects. + # + if self.is_association: + return WMI (moniker=value) + else: + return value + elif self.methods.has_key (attribute): + return self._cached_methods (attribute) + else: + return getattr (self.ole_object, attribute) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __setattr__ (self, attribute, value): + """ + If the attribute to be set is valid for the proxied + COM object, set that objects's parameter value; if not, + raise an exception. + """ + try: + if self.properties.has_key (attribute): + self._cached_properties (attribute).Value = value + if self.ole_object.Path_.Path: + self.ole_object.Put_ () + else: + raise AttributeError, attribute + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __eq__ (self, other): + """ + Use WMI's CompareTo_ to compare this object with + another. Don't try to do anything if the other + object is not a wmi object. It might be possible + to compare this object's unique key with a string + or something, but this doesn't seem to be universal + enough to merit a special case. + """ + if isinstance (other, self.__class__): + return self.ole_object.CompareTo_ (other.ole_object) + else: + raise x_wmi, "Can't compare a WMI object with something else" + + def put (self): + self.ole_object.Put_ () + + def set (self, **kwargs): + """ + Set several properties of the underlying object + at one go. This is particularly useful in combination + with the new () method below. However, an instance + which has been spawned in this way won't have enough + information to write pack, so only try if the + instance has a path. + """ + if kwargs: + try: + for attribute, value in kwargs.items (): + if self.properties.has_key (attribute): + self._cached_properties (attribute).Value = value + else: + raise AttributeError, attribute + # + # Only try to write the attributes + # back if the object exists. + # + if self.ole_object.Path_.Path: + self.ole_object.Put_ () + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def path (self): + """ + Return the WMI URI to this object. Can be used to + determine the path relative to the parent namespace. eg, + + <pre class="code"> + pp0 = wmi.WMI ().Win32_ParallelPort ()[0] + print pp0.path ().RelPath + </pre> + """ + try: + return self.ole_object.Path_ + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def derivation (self): + """Return a tuple representing the object derivation for + this object, with the most specific object first. eg, + + pp0 = wmi.WMI ().Win32_ParallelPort ()[0] + print ' <- '.join (pp0.derivation ()) + """ + try: + return self.ole_object.Derivation_ + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def associators (self, wmi_association_class="", wmi_result_class=""): + """Return a list of objects related to this one, optionally limited + either by association class (ie the name of the class which relates + them) or by result class (ie the name of the class which would be + retrieved) + + <pre class="code"> +c = wmi.WMI () +pp = c.Win32_ParallelPort ()[0] + +for i in pp.associators (wmi_association_class="Win32_PortResource"): + print i + +for i in pp.associators (wmi_result_class="Win32_PnPEntity"): + print i + </pre> + """ + try: + return [ + _wmi_object (i) for i in \ + self.ole_object.Associators_ ( + strAssocClass=wmi_association_class, + strResultClass=wmi_result_class + ) + ] + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def references (self, wmi_class=""): + """Return a list of associations involving this object, optionally + limited by the result class (the name of the association class). + + NB Associations are treated specially; although WMI only returns + the string corresponding to the instance of each associated object, + this module will automatically convert that to the object itself. + + <pre class="code"> + c = wmi.WMI () + sp = c.Win32_SerialPort ()[0] + + for i in sp.references (): + print i + + for i in sp.references (wmi_class="Win32_SerialPortSetting"): + print i + </pre> + """ + try: + return [_wmi_object (i) for i in self.ole_object.References_ (strResultClass=wmi_class)] + except pywintypes.com_error, error_info: + handle_com_error (error_info) + +# +# class _wmi_class +# +class _wmi_class (_wmi_object): + """Currying class to assist in issuing queries against + a WMI namespace. The idea is that when someone issues + an otherwise unknown method against the WMI object, if + it matches a known WMI class a query object will be + returned which may then be called with one or more params + which will form the WHERE clause. eg, + + <pre class="code"> + c = wmi.WMI () + c_drive = c.Win32_LogicalDisk (Name='C:') + </pre> + """ + def __init__ (self, namespace, wmi_class): + _wmi_object.__init__ (self, wmi_class) + _set (self, "_namespace", namespace) + _set (self, "_class_name", wmi_class.Path_.Class) + + def query (self, fields=[], **where_clause): + """Make it slightly easier to query against the class, + by calling the namespace's query with the class preset. + Won't work if the class has been instantiated directly. + """ + if self._namespace is None: + raise x_wmi_no_namespace, "You cannot query directly from a WMI class" + + try: + field_list = ", ".join (fields) or "*" + wql = "SELECT " + field_list + " FROM " + self._class_name + if where_clause: + wql += " WHERE " + " AND ". join (["%s = '%s'" % (k, v) for k, v in where_clause.items ()]) + return self._namespace.query (wql, self, fields) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + __call__ = query + + def watch_for ( + self, + notification_type=None, + delay_secs=1, + **where_clause + ): + if self._namespace is None: + raise x_wmi_no_namespace, "You cannot watch directly from a WMI class" + + return self._namespace.watch_for ( + notification_type=notification_type, + wmi_class=self._class_name, + delay_secs=delay_secs, + **where_clause + ) + + def instances (self): + """Return a list of instances of the WMI class + """ + try: + return [_wmi_object (instance, self) for instance in self.Instances_ ()] + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def new (self, **kwargs): + """This is the equivalent to the raw-WMI SpawnInstance_ + method. Note that there are relatively few uses for + this, certainly fewer than you might imagine. Most + classes which need to create a new *real* instance + of themselves, eg Win32_Process, offer a .Create + method. SpawnInstance_ is generally reserved for + instances which are passed as parameters to such + .Create methods, a common example being the + Win32_SecurityDescriptor, passed to Win32_Share.Create + and other instances which need security. + + The example here is Win32_ProcessStartup, which + controls the shown/hidden state etc. of a new + Win32_Process instance. + + <pre class="code"> + import win32con + import wmi + c = wmi.WMI () + startup = c.Win32_ProcessStartup.new (ShowWindow=win32con.SW_SHOWMINIMIZED) + pid, retval = c.Win32_Process.Create ( + CommandLine="notepad.exe", + ProcessStartupInformation=startup + ) + </pre> + + NB previous versions of this module, used this function + to create new process. This is *not* a good example + of its use; it is better handled with something like + the example above. + """ + try: + obj = _wmi_object (self.SpawnInstance_ (), self) + obj.set (**kwargs) + return obj + except pywintypes.com_error, error_info: + handle_com_error (error_info) + +# +# class _wmi_result +# +class _wmi_result: + """Simple, data only result for targeted WMI queries which request + data only result classes via fetch_as_classes. + """ + def __init__(self, obj, attributes): + if attributes: + for attr in attributes: + self.__dict__[attr] = obj.Properties_ (attr).Value + else: + for p in obj.Properties_: + attr = p.Name + self.__dict__[attr] = obj.Properties_(attr).Value + +# +# class WMI +# +class _wmi_namespace: + """A WMI root of a computer system. The classes attribute holds a list + of the classes on offer. This means you can explore a bit with + things like this: + + <pre class="code"> + c = wmi.WMI () + for i in c.classes: + if "user" in i.lower (): + print i + </pre> + """ + def __init__ (self, namespace, find_classes): + _set (self, "_namespace", namespace) + # + # wmi attribute preserved for backwards compatibility + # + _set (self, "wmi", namespace) + + # Initialise the "classes" attribute, to avoid infinite recursion in the + # __getattr__ method (which uses it). + self.classes = {} + # + # Pick up the list of classes under this namespace + # so that they can be queried, and used as though + # properties of the namespace by means of the __getattr__ + # hook below. + # If the namespace does not support SubclassesOf, carry on + # regardless + # + if find_classes: + try: + self.classes.update (self.subclasses_of ()) + except AttributeError: + pass + + def __repr__ (self): + return "<_wmi_namespace: %s>" % self.wmi + + def __str__ (self): + return repr (self) + + def get (self, moniker): + try: + return _wmi_object (self.wmi.Get (moniker)) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def handle (self): + """The raw OLE object representing the WMI namespace""" + return self._namespace + + def subclasses_of (self, root="", regex=r".*"): + classes = {} + for c in self._namespace.SubclassesOf (root): + klass = c.Path_.Class + if re.match (regex, klass): + classes[klass] = None + return classes + + def instances (self, class_name): + """Return a list of instances of the WMI class. This is + (probably) equivalent to querying with no qualifiers. + + <pre class="code"> + system.instances ("Win32_LogicalDisk") + # should be the same as + system.Win32_LogicalDisk () + </pre> + """ + try: + return [_wmi_object (obj) for obj in self._namespace.InstancesOf (class_name)] + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def new (self, wmi_class, **kwargs): + """This is now implemented by a call to _wmi_namespace.new (qv)""" + return getattr (self, wmi_class).new (**kwargs) + + new_instance_of = new + + def _raw_query (self, wql): + """Execute a WQL query and return its raw results. Use the flags + recommended by Microsoft to achieve a read-only, semi-synchronous + query where the time is taken while looping through. Should really + be a generator, but ... + NB Backslashes need to be doubled up. + """ + flags = wbemFlagReturnImmediately | wbemFlagForwardOnly + wql = wql.replace ("\\", "\\\\") + if _DEBUG: print "_raw_query(wql):", wql + try: + return self._namespace.ExecQuery (strQuery=wql, iFlags=flags) + except pywintypes.com_error, (hresult, hresult_text, additional, param_in_error): + raise WMI_EXCEPTIONS.get (hresult, x_wmi (hresult)) + + def query (self, wql, instance_of=None, fields=[]): + """Perform an arbitrary query against a WMI object, and return + a list of _wmi_object representations of the results. + """ + return [ _wmi_object (obj, instance_of, fields) for obj in self._raw_query(wql) ] + + def fetch_as_classes (self, wmi_classname, fields=(), **where_clause): + """Build and execute a wql query to fetch the specified list of fields from + the specified wmi_classname + where_clause, then return the results as + a list of simple class instances with attributes matching fields_list. + + If fields is left empty, select * and pre-load all class attributes for + each class returned. + """ + wql = "SELECT %s FROM %s" % (fields and ", ".join (fields) or "*", wmi_classname) + if where_clause: + wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) + return [_wmi_result (obj, fields) for obj in self._raw_query(wql)] + + def fetch_as_lists (self, wmi_classname, fields, **where_clause): + """Build and execute a wql query to fetch the specified list of fields from + the specified wmi_classname + where_clause, then return the results as + a list of lists whose values correspond fields_list. + """ + wql = "SELECT %s FROM %s" % (", ".join (fields), wmi_classname) + if where_clause: + wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) + results = [] + for obj in self._raw_query(wql): + results.append ([obj.Properties_ (field).Value for field in fields]) + return results + + def watch_for ( + self, + raw_wql=None, + notification_type=None, + wmi_class=None, + delay_secs=1, + **where_clause + ): + """Set up an event tracker on a WMI event. This function + returns an wmi_watcher which can be called to get the + next event. eg, + + <pre class="code"> + c = wmi.WMI () + + raw_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'" + watcher = c.watch_for (raw_wql=raw_wql) + while 1: + process_created = watcher () + print process_created.Name + + # or + + watcher = c.watch_for ( + notification_type="Creation", + wmi_class="Win32_Process", + delay_secs=2, + Name='calc.exe' + ) + calc_created = watcher () + </pre> + + Now supports timeout on the call to watcher, eg: + + <pre class="code"> + import pythoncom + import wmi + c = wmi.WMI (privileges=["Security"]) + watcher1 = c.watch_for ( + notification_type="Creation", + wmi_class="Win32_NTLogEvent", + Type="error" + ) + watcher2 = c.watch_for ( + notification_type="Creation", + wmi_class="Win32_NTLogEvent", + Type="warning" + ) + + while 1: + try: + error_log = watcher1 (500) + except wmi.x_wmi_timed_out: + pythoncom.PumpWaitingMessages () + else: + print error_log + + try: + warning_log = watcher2 (500) + except wmi.x_wmi_timed_out: + pythoncom.PumpWaitingMessages () + else: + print warning_log + </pre> + """ + class_name = wmi_class + if raw_wql: + wql = raw_wql + else: + if where_clause: + where = " AND " + " AND ".join (["TargetInstance.%s = '%s'" % (k, v) for k, v in where_clause.items ()]) + else: + where = "" + wql = \ + "SELECT * FROM __Instance%sEvent WITHIN %d WHERE TargetInstance ISA '%s' %s" % \ + (notification_type, delay_secs, class_name, where) + + if _DEBUG: print wql + + try: + return _wmi_watcher (self._namespace.ExecNotificationQuery (wql)) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __getattr__ (self, attribute): + """Offer WMI classes as simple attributes. Pass through any untrapped + unattribute to the underlying OLE object. This means that new or + unmapped functionality is still available to the module user. + """ + # + # Don't try to match against known classes as was previously + # done since the list may not have been requested + # (find_classes=False). + # + try: + return self._cached_classes (attribute) + except pywintypes.com_error, error_i... [truncated message content] |
From: <ti...@us...> - 2007-01-26 02:16:38
|
Revision: 79 http://pymoul.svn.sourceforge.net/pymoul/?rev=79&view=rev Author: tiran Date: 2007-01-25 18:16:36 -0800 (Thu, 25 Jan 2007) Log Message: ----------- Lot's of changes: Cleanup logging New singleapp module added Restrict to one instance of moulqt Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/file/tests/test_localization.py pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/qt/moulqt.py pymoul/trunk/src/moul/qt/ui/mainwindow.py Added Paths: ----------- pymoul/trunk/src/moul/osdependent/singleapp.py pymoul/trunk/src/moul/osdependent/tests/ pymoul/trunk/src/moul/osdependent/tests/__init__.py pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/config/__init__.py 2007-01-26 02:16:36 UTC (rev 79) @@ -19,8 +19,9 @@ """ import os import sys +from logging import getLogger -from moul.log import LOG +LOG = getLogger('pyMoul') # a program under py2exe is sys.frozen __FROZEN__ = bool(getattr(sys, 'frozen', False)) Modified: pymoul/trunk/src/moul/file/tests/test_localization.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_localization.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/file/tests/test_localization.py 2007-01-26 02:16:36 UTC (rev 79) @@ -41,13 +41,13 @@ def test_parseLocDir(self): parseLocDirectory(base) - key = (u'testage', u'testset', u'testelement', u'english') + key = (u'english', u'testage', u'testset', u'testelement') self.failUnless(key in translationRegistry, translationRegistry.keys()) self.failUnlessEqual(len(translationRegistry), 1) def test_parseLoc(self): parseLoc(os.path.join(base, 'test.loc')) - key = (u'testage', u'testset', u'testelement', u'english') + key = (u'english', u'testage', u'testset', u'testelement') self.failUnless(key in translationRegistry, translationRegistry.keys()) self.failUnlessEqual(len(translationRegistry), 1) Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-01-26 02:16:36 UTC (rev 79) @@ -161,7 +161,7 @@ Constrain() is a NOOP >>> c = Constrain('foo', False, object) - >>> c('dummy') + >>> c('dummy', debug="name") 'dummy' """ __slots__ = () @@ -175,21 +175,21 @@ """Min / max constrain >>> c = MinMax(1, 10) - >>> c(1) + >>> c(1, debug="name") 1 - >>> c(10) + >>> c(10, debug="name") 10 - >>> c(11) + >>> c(11, debug="name") Traceback (most recent call last): ... - ConstrainError: 11 > max 10 - >>> c(-1) + ConstrainError: name: 11 > max 10 + >>> c(-1, debug="name") Traceback (most recent call last): ... - ConstrainError: -1 < min 1 + ConstrainError: name: -1 < min 1 >>> c = MinMax(0, 1) - >>> c(0.5) + >>> c(0.5, debug="name") 0.5 """ __slots__ = ('_min', '_max') @@ -210,16 +210,16 @@ """Constrain for video mode indexes >>> v = VideoConstrain() - >>> v(0) + >>> v(0, debug="name") 0 - >>> v(-1) + >>> v(-1, debug="name") Traceback (most recent call last): ... - ConstrainError: -1 < min 0 - >>> v(11) + ConstrainError: name: -1 < min 0 + >>> v(11, debug="name") Traceback (most recent call last): ... - ConstrainError: 11 > max 10 + ConstrainError: name: 11 > max 10 """ def __init__(self): self._min = 0 @@ -229,12 +229,12 @@ """value in list constrain >>> c = Contains((1, 2, 3)) - >>> c(1) + >>> c(1, debug="name") 1 - >>> c(4) + >>> c(4, debug="name") Traceback (most recent call last): ... - ConstrainError: 4 not in (1, 2, 3) + ConstrainError: name: 4 not in (1, 2, 3) """ __slots__ = ('_values') def __init__(self, values): Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/log.py 2007-01-26 02:16:36 UTC (rev 79) @@ -27,17 +27,23 @@ import sys import platform import logging +from logging import Formatter from logging import handlers - from moul.metadata import __version__ as moul_version -# alias getLogger = logging.getLogger # copied from moul.config to prevent circular imports __FROZEN__ = bool(getattr(sys, 'frozen', False)) __LOG_SIGNALS__ = not __FROZEN__ +format = Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', + #'%a, %d %b %Y %H:%M:%S' + '%m-%d %H:%M:%S') +root = getLogger() +root.setLevel(logging.DEBUG) +LOG = getLogger('pyMoul') + class LoggingStdout(object): """Replacement for stdout/stderr IO """ @@ -52,18 +58,50 @@ if value: self._logfunc(value) -format = logging.Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', - #'%a, %d %b %Y %H:%M:%S' - '%m-%d %H:%M:%S') -root = getLogger() -root.setLevel(logging.DEBUG) +mhdlr = None +fhdlr = None +def _installMemoryHdlr(): + """setup a memory handler to store records before we have the + infrastructure to log events to a file + """ + global mhdlr + mhdlr = handlers.MemoryHandler(capacity=4*1024) # MemoryHandler doesn't flush w/o a target + mhdlr.setFormatter(format) + root.addHandler(mhdlr) -# setup a memory handler to store records before we have the infrastructure -# to log events to a file -mhdlr = handlers.MemoryHandler(capacity=16*1024) # MemoryHandler doesn't flush w/o a target -mhdlr.setFormatter(format) -root.addHandler(mhdlr) +def _removeMemoryHdlr(): + """Remove memory handler + """ + global mhdlr + global fhdlr + mhdlr.setTarget(fhdlr) + mhdlr.flush() + root.removeHandler(mhdlr) + del mhdlr +def _installFileHdlr(): + """Install a file handler + """ + global fhdlr + from moul.config import getPyMoulDataDir + logFile = os.path.join(getPyMoulDataDir(check=True), 'pymoul.log') + LOG.debug("Adding file logger: %s" % logFile) + fhdlr = handlers.RotatingFileHandler(logFile, backupCount=9) + fhdlr.setFormatter(format) + root.addHandler(fhdlr) + fhdlr.doRollover() + +def _systemInfo(): + LOG.debug("pyMoul version: %s" % moul_version) + LOG.debug("Python: %s" % repr(sys.version_info)) + LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) + LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) + LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" + % platform.uname()) + LOG.debug("platform name: %s" % platform.platform(True)) + +# no setup the logging stuff! + if not __FROZEN__: # Add streaming handler to sys.stderr. # Only log to stderr when the program is not frozen! @@ -71,37 +109,14 @@ shdlr.setFormatter(format) root.addHandler(shdlr) else: + _installMemoryHdlr() # Redirect stdout and stderr to logger when running as frozen app sys.stdout = LoggingStdout(getLogger('stdout').info) - print "Stdout redirected" sys.stderr = LoggingStdout(getLogger('stderr').error) - print >>sys.stderr, "Stderr redirected" + _systemInfo() + _installFileHdlr() + _removeMemoryHdlr() -# DEBUG system infos -LOG = getLogger('pyMoul') -LOG.debug("pyMoul version: %s" % moul_version) -LOG.debug("Python: %s" % repr(sys.version_info)) -LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) -LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) -LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" - % platform.uname()) -LOG.debug("platform name: %s" % platform.platform(True)) - -# now get the pymoul userdata dir -from moul.config import getPyMoulDataDir -logFile = os.path.join(getPyMoulDataDir(check=True), 'pymoul.log') -LOG.debug("Adding file logger: %s" % logFile) -fhdlr = handlers.RotatingFileHandler(logFile, backupCount=9) -fhdlr.setFormatter(format) -root.addHandler(fhdlr) -fhdlr.doRollover() - -# flush and remove memory handler -mhdlr.setTarget(fhdlr) -mhdlr.flush() -root.removeHandler(mhdlr) -del mhdlr - def signalLogDecorator(__logger__): """Decorator to log signals Added: pymoul/trunk/src/moul/osdependent/singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/singleapp.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-26 02:16:36 UTC (rev 79) @@ -0,0 +1,184 @@ +# 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 +# +"""Simple single instance application + +Includes portalocker code with minor tweaks for Python 2.4+ + Author: Jonathan Feinberg <jd...@po...> + Version: $Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp $ + http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65203 + +Boiler plate +>>> import sys +>>> from shutil import rmtree +>>> from subprocess import call +>>> tmpdir = tempfile.mkdtemp() +>>> testfile = os.path.join(tmpdir, 'test.lck') +>>> if os.name == 'nt': +... rm = "del" +... else: +... rm = "rm" + +Create a file and lock it for this process +>>> flags = LOCK_SH | LOCK_NB +>>> fd1 = open(testfile, 'w') +>>> fn1 = fd1.fileno() +>>> lock(fd1, flags) +>>> fd1.write('testdata') + +Try to delete the file from another process +>>> try: +... retcode = call("%s %s" % (rm, testfile)) +... except: +... typ, value, tb = sys.exc_info() +... del tb +... else: +... print "Should have raised an error!" + +On Windows the error is WindowsError based on OSError +>>> issubclass(typ, OSError) or typ +True + +Clean up +>>> unlock(fd1) +>>> fd1.close() +>>> rmtree(tmpdir) + +>>> singleapp = SimpleSingleApp('testapp') +>>> lckfile = singleapp.lckfile +>>> if os.path.isfile(lckfile): +... os.unlink(fpath) +>>> path, pid = singleapp.acquire() +>>> path == lckfile +True +>>> os.path.isfile(lckfile) +True +>>> singleapp.checkLocked() is None +True +>>> singleapp.release() +>>> os.path.isfile(lckfile) +False +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import os +import getpass +import tempfile +import atexit + +TEMPDIR = tempfile.gettempdir() +USER = getpass.getuser() +PID = os.getpid() + +if os.name == 'nt': + import win32con + import win32file + import pywintypes + LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK + LOCK_SH = 0 # the default + LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY + lowbits, highbits = 0, -65536 +elif os.name == 'posix': + import fcntl + LOCK_EX = fcntl.LOCK_EX + LOCK_SH = fcntl.LOCK_SH + LOCK_NB = fcntl.LOCK_NB +else: + raise RuntimeError("PortaLocker only defined for nt and posix platforms") + +if os.name == 'nt': + def lock(file, flags): + hfile = win32file._get_osfhandle(file.fileno()) + return win32file.LockFileEx(hfile, flags, lowbits, highbits, pywintypes.OVERLAPPED()) + def unlock(file): + hfile = win32file._get_osfhandle(file.fileno()) + return win32file.UnlockFileEx(hfile, lowbits, highbits, pywintypes.OVERLAPPED()) +elif os.name =='posix': + def lock(file, flags): + return fcntl.flock(file.fileno(), flags) + def unlock(file): + return fcntl.flock(file.fileno(), fcntl.LOCK_UN) + +class SingleAppError(OSError): + pass + +class SimpleSingleApp(object): + """A simple single instance application implemementation + """ + flags = LOCK_SH | LOCK_NB + + def __init__(self, appname, path=TEMPDIR, user=USER, pid=PID, ext='.lck', + *args): + self.appname = appname + self.user = user + self.path = path + self.args = args + self.pid = pid + self.ext = ext + self._fd = None + self.lckfile = self._genFilename() + # register atexit function + atexit.register(self.release) + + def acquire(self): + """Acquire lock + + May raise an OSError + """ + try: + self._fd = open(self.lckfile, 'w') + self._fd.write(str(self.pid)) + self._fd.flush() + lock(self._fd, self.flags) + except (OSError, IOError): + self._fd.close() + self._fd = None + raise SingleAppError("Another instance is already running") + return self.lckfile, self.pid + + def release(self): + """Release lock + """ + try: + unlock(self._fd) + except (SystemError, SyntaxError): + raise + except: + pass + if self._fd: + self._fd.close() + if os.path.isfile(self.lckfile): + os.unlink(self.lckfile) + + def checkLocked(self): + """Check if another process has a lock + """ + try: + fd = open(self.lckfile, 'a+') + fd.close() + except OSError: + return True + else: + if self._fd: + return None + return False + + def _genFilename(self): + fname = '_'.join((self.appname, self.user,) + self.args) + self.ext + return os.path.join(self.path, fname) Property changes on: pymoul/trunk/src/moul/osdependent/singleapp.py ___________________________________________________________________ Name: svn:eol-style + native Added: pymoul/trunk/src/moul/osdependent/tests/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/tests/__init__.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/tests/__init__.py 2007-01-26 02:16:36 UTC (rev 79) @@ -0,0 +1,22 @@ +# 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 +# +""" +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" Property changes on: pymoul/trunk/src/moul/osdependent/tests/__init__.py ___________________________________________________________________ Name: svn:eol-style + native Added: pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py 2007-01-26 02:16:36 UTC (rev 79) @@ -0,0 +1,39 @@ +# 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 +# +"""moul.osdependent.singleapp +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import unittest +from doctest import DocTestSuite + +from moul.osdependent.singleapp import SimpleSingleApp +from moul.osdependent.singleapp import lock +from moul.osdependent.singleapp import unlock +from moul.osdependent.singleapp import LOCK_EX, LOCK_SH, LOCK_NB + +def test_suite(): + return unittest.TestSuite(( + DocTestSuite('moul.osdependent.singleapp'), + )) + +if __name__ == '__main__': + unittest.main(defaultTest="test_suite") + Property changes on: pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py ___________________________________________________________________ Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 02:16:36 UTC (rev 79) @@ -27,9 +27,24 @@ from PyQt4 import QtGui from moul.qt.mainwindow import MainWindow +from moul.osdependent.singleapp import SimpleSingleApp +from moul.config import getPyMoulDataDir def main(*args): app = QtGui.QApplication(*args) + singleapp = SimpleSingleApp('pymoulqt', path=getPyMoulDataDir()) + try: + singleapp.acquire() + except OSError: + mb = QtGui.QMessageBox() + mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) + mb.setIcon(QtGui.QMessageBox.Critical) + mb.setWindowTitle(app.trUtf8("Already running")) + mb.setText(app.trUtf8("""An instance of pyMoul QT is already running!""")) + mb.setStandardButtons(QtGui.QMessageBox.Close) + mb.exec_() + sys.exit(1) + mainWindow = MainWindow() mainWindow.show() return app.exec_() Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-26 02:16:36 UTC (rev 79) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src\moul\qt\ui\mainwindow.ui' # -# Created: Thu Jan 25 19:53:15 2007 +# Created: Thu Jan 25 19:55:32 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-25 18:54:52
|
Revision: 78 http://pymoul.svn.sourceforge.net/pymoul/?rev=78&view=rev Author: tiran Date: 2007-01-25 10:54:52 -0800 (Thu, 25 Jan 2007) Log Message: ----------- Doc tab no works only on my computer - infrastructure isn't present Modified Paths: -------------- pymoul/trunk/src/moul/qt/localization.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.ui Modified: pymoul/trunk/src/moul/qt/localization.py =================================================================== --- pymoul/trunk/src/moul/qt/localization.py 2007-01-25 18:50:37 UTC (rev 77) +++ pymoul/trunk/src/moul/qt/localization.py 2007-01-25 18:54:52 UTC (rev 78) @@ -22,6 +22,7 @@ __revision__ = "$Revision$" import sys +import os from PyQt4 import QtGui from PyQt4 import QtCore @@ -45,8 +46,12 @@ """Mixin for documents tab """ def _documents_init(self): + locDir = lookupDir('loc') + if not os.path.isdir(locDir): + return + self.tab_documents.setEnabled(True) - locDir = lookupDir('loc') + parseLocDirectory(locDir) self._documents_state = {} Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-25 18:50:37 UTC (rev 77) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-25 18:54:52 UTC (rev 78) @@ -68,7 +68,7 @@ self._ping_init() self._systray_init() self.tab_documents.setEnabled(False) - #self._documents_init() + self._documents_init() def _notimplemented(self): """TODO: remove me Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-25 18:50:37 UTC (rev 77) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-25 18:54:52 UTC (rev 78) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src\moul\qt\ui\mainwindow.ui' # -# Created: Thu Jan 25 19:49:10 2007 +# Created: Thu Jan 25 19:53:15 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -554,10 +554,6 @@ self.groupBox_voicechat.setGeometry(QtCore.QRect(10,150,431,71)) self.groupBox_voicechat.setObjectName("groupBox_voicechat") - self.cb_aud_voicechat = QtGui.QCheckBox(self.groupBox_voicechat) - self.cb_aud_voicechat.setGeometry(QtCore.QRect(250,30,111,19)) - self.cb_aud_voicechat.setObjectName("cb_aud_voicechat") - self.verticalLayout_13 = QtGui.QWidget(self.groupBox_voicechat) self.verticalLayout_13.setGeometry(QtCore.QRect(20,20,179,43)) self.verticalLayout_13.setObjectName("verticalLayout_13") @@ -586,22 +582,21 @@ self.sl_aud_microphon.setTickInterval(25) self.sl_aud_microphon.setObjectName("sl_aud_microphon") self.vboxlayout13.addWidget(self.sl_aud_microphon) + + self.cb_aud_voicechat = QtGui.QCheckBox(self.groupBox_voicechat) + self.cb_aud_voicechat.setGeometry(QtCore.QRect(250,30,171,19)) + self.cb_aud_voicechat.setObjectName("cb_aud_voicechat") self.tabwidget.addTab(self.tab_audio,"") self.tab_time = QtGui.QWidget() self.tab_time.setObjectName("tab_time") - self.gb_dnitime = QtGui.QGroupBox(self.tab_time) - self.gb_dnitime.setEnabled(True) - self.gb_dnitime.setGeometry(QtCore.QRect(10,120,431,221)) - self.gb_dnitime.setObjectName("gb_dnitime") - self.gb_caverntime = QtGui.QGroupBox(self.tab_time) self.gb_caverntime.setGeometry(QtCore.QRect(10,10,431,101)) self.gb_caverntime.setObjectName("gb_caverntime") self.gridLayout = QtGui.QWidget(self.gb_caverntime) - self.gridLayout.setGeometry(QtCore.QRect(10,20,381,71)) + self.gridLayout.setGeometry(QtCore.QRect(10,20,411,71)) self.gridLayout.setObjectName("gridLayout") self.gridlayout = QtGui.QGridLayout(self.gridLayout) @@ -661,6 +656,11 @@ self.label_12 = QtGui.QLabel(self.gridLayout) self.label_12.setObjectName("label_12") self.gridlayout.addWidget(self.label_12,1,3,1,1) + + self.gb_dnitime = QtGui.QGroupBox(self.tab_time) + self.gb_dnitime.setEnabled(False) + self.gb_dnitime.setGeometry(QtCore.QRect(10,120,431,221)) + self.gb_dnitime.setObjectName("gb_dnitime") self.tabwidget.addTab(self.tab_time,"") self.tab_ping = QtGui.QWidget() @@ -758,7 +758,7 @@ MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) - self.tabwidget.setCurrentIndex(4) + self.tabwidget.setCurrentIndex(0) QtCore.QObject.connect(self.main_buttonbox,QtCore.SIGNAL("rejected()"),MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -801,10 +801,9 @@ self.lb_aud_device.setText(QtGui.QApplication.translate("MainWindow", "Generic Software", None, QtGui.QApplication.UnicodeUTF8)) self.cb_aud_eax.setText(QtGui.QApplication.translate("MainWindow", "Enable EAX", None, QtGui.QApplication.UnicodeUTF8)) self.groupBox_voicechat.setTitle(QtGui.QApplication.translate("MainWindow", "Voice chat", None, QtGui.QApplication.UnicodeUTF8)) + self.lb_aud_microphon.setText(QtGui.QApplication.translate("MainWindow", "Microphon Level", None, QtGui.QApplication.UnicodeUTF8)) self.cb_aud_voicechat.setText(QtGui.QApplication.translate("MainWindow", "Enable Voice Chat", None, QtGui.QApplication.UnicodeUTF8)) - self.lb_aud_microphon.setText(QtGui.QApplication.translate("MainWindow", "Microphon Level", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_audio), QtGui.QApplication.translate("MainWindow", "Audio", None, QtGui.QApplication.UnicodeUTF8)) - self.gb_dnitime.setTitle(QtGui.QApplication.translate("MainWindow", "D\'ni time", None, QtGui.QApplication.UnicodeUTF8)) self.gb_caverntime.setTitle(QtGui.QApplication.translate("MainWindow", "Time zones", None, QtGui.QApplication.UnicodeUTF8)) self.label_4.setText(QtGui.QApplication.translate("MainWindow", "Cavern time:", None, QtGui.QApplication.UnicodeUTF8)) self.label_5.setText(QtGui.QApplication.translate("MainWindow", "Cyan time:", None, QtGui.QApplication.UnicodeUTF8)) @@ -812,6 +811,7 @@ self.lb_cavern_utc.setText(QtGui.QApplication.translate("MainWindow", "UTC -0", None, QtGui.QApplication.UnicodeUTF8)) self.label_11.setText(QtGui.QApplication.translate("MainWindow", "(Mountain Standard Time)", None, QtGui.QApplication.UnicodeUTF8)) self.label_12.setText(QtGui.QApplication.translate("MainWindow", "(Pacific Standard Time)", None, QtGui.QApplication.UnicodeUTF8)) + self.gb_dnitime.setTitle(QtGui.QApplication.translate("MainWindow", "D\'ni time", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_time), QtGui.QApplication.translate("MainWindow", "Time", None, QtGui.QApplication.UnicodeUTF8)) self.gb_servers.setTitle(QtGui.QApplication.translate("MainWindow", "Ping servers", None, QtGui.QApplication.UnicodeUTF8)) self.button_ping.setText(QtGui.QApplication.translate("MainWindow", "Ping", None, QtGui.QApplication.UnicodeUTF8)) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.ui =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-25 18:50:37 UTC (rev 77) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-25 18:54:52 UTC (rev 78) @@ -147,7 +147,7 @@ <enum>QTabWidget::North</enum> </property> <property name="currentIndex" > - <number>4</number> + <number>0</number> </property> <widget class="QWidget" name="tab_graphics" > <attribute name="title" > @@ -1173,19 +1173,6 @@ <property name="title" > <string>Voice chat</string> </property> - <widget class="QCheckBox" name="cb_aud_voicechat" > - <property name="geometry" > - <rect> - <x>250</x> - <y>30</y> - <width>111</width> - <height>19</height> - </rect> - </property> - <property name="text" > - <string>Enable Voice Chat</string> - </property> - </widget> <widget class="QWidget" name="verticalLayout_13" > <property name="geometry" > <rect> @@ -1251,28 +1238,25 @@ </item> </layout> </widget> + <widget class="QCheckBox" name="cb_aud_voicechat" > + <property name="geometry" > + <rect> + <x>250</x> + <y>30</y> + <width>171</width> + <height>19</height> + </rect> + </property> + <property name="text" > + <string>Enable Voice Chat</string> + </property> + </widget> </widget> </widget> <widget class="QWidget" name="tab_time" > <attribute name="title" > <string>Time</string> </attribute> - <widget class="QGroupBox" name="gb_dnitime" > - <property name="enabled" > - <bool>true</bool> - </property> - <property name="geometry" > - <rect> - <x>10</x> - <y>120</y> - <width>431</width> - <height>221</height> - </rect> - </property> - <property name="title" > - <string>D'ni time</string> - </property> - </widget> <widget class="QGroupBox" name="gb_caverntime" > <property name="geometry" > <rect> @@ -1290,7 +1274,7 @@ <rect> <x>10</x> <y>20</y> - <width>381</width> + <width>411</width> <height>71</height> </rect> </property> @@ -1397,6 +1381,22 @@ </layout> </widget> </widget> + <widget class="QGroupBox" name="gb_dnitime" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="geometry" > + <rect> + <x>10</x> + <y>120</y> + <width>431</width> + <height>221</height> + </rect> + </property> + <property name="title" > + <string>D'ni time</string> + </property> + </widget> </widget> <widget class="QWidget" name="tab_ping" > <attribute name="title" > This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-25 18:50:40
|
Revision: 77 http://pymoul.svn.sourceforge.net/pymoul/?rev=77&view=rev Author: tiran Date: 2007-01-25 10:50:37 -0800 (Thu, 25 Jan 2007) Log Message: ----------- Added localization document browser Modified Paths: -------------- pymoul/trunk/Makefile pymoul/trunk/src/moul/file/localization.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.ui Added Paths: ----------- pymoul/trunk/src/moul/qt/localization.py Modified: pymoul/trunk/Makefile =================================================================== --- pymoul/trunk/Makefile 2007-01-25 15:25:33 UTC (rev 76) +++ pymoul/trunk/Makefile 2007-01-25 18:50:37 UTC (rev 77) @@ -25,7 +25,7 @@ run: compileui PYTHONPATH="src" $(PYTHON) src/moul/qt/moulqt.py -runexe: compileui py2exe +exerun: compileui py2exe dist/moulqt.exe compileui: Modified: pymoul/trunk/src/moul/file/localization.py =================================================================== --- pymoul/trunk/src/moul/file/localization.py 2007-01-25 15:25:33 UTC (rev 76) +++ pymoul/trunk/src/moul/file/localization.py 2007-01-25 18:50:37 UTC (rev 77) @@ -33,16 +33,24 @@ from xml.sax import make_parser from xml.sax.handler import feature_namespaces -from moul.log import LOG +from moul.log import getLogger +LOG = getLogger('moul loc') -def _add(d, key, value): +def _addList(d, key, value): lst = d.setdefault(key, []) lst.append(value) +def _addTree(d, lang, age, setname, element, key): + dlang = d.setdefault(lang, {}) + dage = dlang.setdefault(age, {}) + dset = dage.setdefault(setname, {}) + dset[element] = key + class TranslationRegistry(dict): """Registry for Translation objects""" - __slot__ = ('_bylanguage', '_byage', '_byset', '_byelement') + __slot__ = ('_bylanguage', '_byage', '_byset', '_byelement', '_tree', + '_ignore_age') def __new__(cls, *args, **kwargs): self = dict.__new__(cls, *args, **kwargs) @@ -50,6 +58,8 @@ self._byage = {} self._byset = {} self._byelement = {} + self._tree = {} + self._ignore_age = [u'OptionsMenu', u'ACA', u'Global', u'KI'] return self def register(self, translation): @@ -59,23 +69,46 @@ (translation.fname, str(key))) LOG.error("TranslationRegistry: %s" % msg) raise KeyError(msg) - _add(self._bylanguage, translation.language, key) - _add(self._byage, translation.age, key) - _add(self._byset, translation.set, key) - _add(self._byelement, translation.element, key) + if translation.age in self._ignore_age: + return + _addList(self._bylanguage, translation.language, key) + _addList(self._byage, translation.age, key) + _addList(self._byset, translation.set, key) + _addList(self._byelement, translation.element, key) + _addTree(self._tree, translation.language, translation.age, + translation.set, translation.element, key) self[key] = translation def __setitem__(self, key, translation): assert key == translation.key() dict.__setitem__(self, key, translation) + def __repr__(self): + return "<%s at %s with %i elements" % (self.__class__.__name__, + id(self), len(self)) + def clear(self): dict.clear(self) self._bylanguage.clear() self._byage.clear() self._byset.clear() self._byelement.clear() + + def languages(self): + return sorted(self._bylanguage.keys()) + def ages(self): + return sorted(self._byage.keys()) + + def sets(self): + return sorted(self._byset.keys()) + + def elements(self): + return sorted(self._byelement.keys()) + + def tree(self): + return self._tree + translationRegistry = TranslationRegistry() registerTranslation = translationRegistry.register @@ -95,11 +128,12 @@ self._set = set self._element = element self._language = language - LOG.debug("New translation file(%s): %s" % (fname, self.key)) + self._fname = fname + #LOG.debug("New translation file(%s): %s" % (fname, self.key)) return self def key(self): - return (self._age, self._set, self._element, self._language) + return (self._language, self._age, self._set, self._element) @property def language(self): return self._language @@ -113,6 +147,9 @@ @property def element(self): return self._element + @property + def fname(self): return self._fname + def __str__(self): return self.content @@ -207,3 +244,18 @@ files.append(fname) return {'files' : files, 'errors' : errors } + +def _test(path="D:/games/MystOnline/dat", out=False): + from pprint import pprint + files, errors = parseLocDirectory(path, clear=True) + if out: + print errors + tr = translationRegistry + print tr.languages() + print tr.ages() + print tr.sets() + print tr.elements() + pprint(tr.tree()) + +if __name__ == '__main__': + _test(out=True) Added: pymoul/trunk/src/moul/qt/localization.py =================================================================== --- pymoul/trunk/src/moul/qt/localization.py (rev 0) +++ pymoul/trunk/src/moul/qt/localization.py 2007-01-25 18:50:37 UTC (rev 77) @@ -0,0 +1,131 @@ +# 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 +# +"""Moul localization / documents +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import sys + +from PyQt4 import QtGui +from PyQt4 import QtCore +from PyQt4.QtCore import Qt +from PyQt4.QtCore import pyqtSignature +from PyQt4.QtCore import SIGNAL + +from moul.config import lookupDir +from moul.file.localization import translationRegistry as tr +from moul.file.localization import parseLocDirectory +from moul.log import getLogger +from moul.log import signalLogDecorator + +LOG = getLogger('moul.loc') + +def insertDummyQ(lst): + dummy = type(lst)(["<choose>"]) + return QtCore.QStringList(dummy+lst) + +class LocalizationMixin(object): + """Mixin for documents tab + """ + def _documents_init(self): + self.tab_documents.setEnabled(True) + locDir = lookupDir('loc') + parseLocDirectory(locDir) + + self._documents_state = {} + + self.connect(self.cb_doc_language, SIGNAL("currentIndexChanged(int)"), + self.on_cb_doc_language_currentIndexChanged) + self.connect(self.cb_doc_age, SIGNAL("currentIndexChanged(int)"), + self.on_cb_doc_age_currentIndexChanged) + self.connect(self.cb_doc_set, SIGNAL("currentIndexChanged(int)"), + self.on_cb_doc_set_currentIndexChanged) + #self.connect(self.cb_doc_element, SIGNAL("currentIndexChanged(int)"), + # self.on_cb_doc_element_currentIndexChanged) + + languages = sorted(tr.languages()) + self._documents_state['languages'] = languages + self.cb_doc_language.addItems(insertDummyQ(languages)) + self.cb_doc_language.setCurrentIndex(0) + + def _documents_clear(self, name): + names = ['language', 'age', 'set', 'element', 'doc'] + for name in names[names.index(name):]: + if name == 'doc': + qobj = self.te_doc_view + else: + qobj = getattr(self, 'cb_doc_%s' % name) + qobj.clear() + qobj.setEnabled(False) + + @pyqtSignature("int") + @signalLogDecorator(LOG) + def on_cb_doc_language_currentIndexChanged(self, idx): + self._documents_clear('age') + if idx <= 0: + return # <choose> + lang = self._documents_state['languages'][idx-1] + ages = sorted(tr._tree[lang].keys()) + self._documents_state['curlanguage'] = lang + self._documents_state['ages'] = ages + self.cb_doc_age.addItems(insertDummyQ(ages)) + self.cb_doc_age.setEnabled(True) + + @pyqtSignature("int") + @signalLogDecorator(LOG) + def on_cb_doc_age_currentIndexChanged(self, idx): + self._documents_clear('set') + if idx <= 0: + return # <choose> + lang = self._documents_state['curlanguage'] + age = self._documents_state['ages'][idx-1] + sets = sorted(tr._tree[lang][age].keys()) + self._documents_state['curage'] = (lang, age) + self._documents_state['sets'] = sets + self.cb_doc_set.addItems(insertDummyQ(sets)) + self.cb_doc_set.setEnabled(True) + + @pyqtSignature("int") + @signalLogDecorator(LOG) + def on_cb_doc_set_currentIndexChanged(self, idx): + self._documents_clear('element') + if idx <= 0: + return # <choose> + lang, age = self._documents_state['curage'] + set = self._documents_state['sets'][idx-1] + elements = sorted(tr._tree[lang][age][set].keys()) + self._documents_state['curset'] = (lang, age, set) + self._documents_state['elements'] = elements + self.cb_doc_element.addItems(insertDummyQ(elements)) + self.cb_doc_element.setEnabled(True) + + @pyqtSignature("int") + @signalLogDecorator(LOG) + def on_cb_doc_element_currentIndexChanged(self, idx): + self._documents_clear('doc') + if idx <= 0: + return # <choose> + lang, age, set = self._documents_state['curset'] + element = self._documents_state['elements'][idx-1] + translation = tr[(lang, age, set, element)] + qstr = QtCore.QString(translation) + self.te_doc_view.setPlainText(qstr) + self.te_doc_view.setEnabled(True) + Property changes on: pymoul/trunk/src/moul/qt/localization.py ___________________________________________________________________ Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-25 15:25:33 UTC (rev 76) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-25 18:50:37 UTC (rev 77) @@ -32,6 +32,7 @@ from PyQt4.QtCore import SIGNAL from moul.qt.ui.mainwindow import Ui_MainWindow +from moul.qt.localization import LocalizationMixin from moul.config import lookupDir from moul.file.wdysini import AudioIni from moul.file.wdysini import GraphicsIni @@ -44,7 +45,7 @@ LOG = getLogger('moul.qt') -class MainWindow(QtGui.QMainWindow, Ui_MainWindow): +class MainWindow(QtGui.QMainWindow, Ui_MainWindow, LocalizationMixin): def __init__(self): QtGui.QMainWindow.__init__(self) # Set up the user interface from Designer. @@ -66,6 +67,8 @@ self._audio_init() self._ping_init() self._systray_init() + self.tab_documents.setEnabled(False) + #self._documents_init() def _notimplemented(self): """TODO: remove me Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-25 15:25:33 UTC (rev 76) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-25 18:50:37 UTC (rev 77) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src\moul\qt\ui\mainwindow.ui' # -# Created: Wed Jan 24 19:26:57 2007 +# Created: Thu Jan 25 19:49:10 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -682,6 +682,67 @@ self.text_ping.setObjectName("text_ping") self.tabwidget.addTab(self.tab_ping,"") + self.tab_documents = QtGui.QWidget() + self.tab_documents.setObjectName("tab_documents") + + self.gb_documents = QtGui.QGroupBox(self.tab_documents) + self.gb_documents.setGeometry(QtCore.QRect(10,0,431,341)) + self.gb_documents.setObjectName("gb_documents") + + self.gridLayout_2 = QtGui.QWidget(self.gb_documents) + self.gridLayout_2.setGeometry(QtCore.QRect(10,20,411,100)) + self.gridLayout_2.setObjectName("gridLayout_2") + + self.gridlayout1 = QtGui.QGridLayout(self.gridLayout_2) + self.gridlayout1.setMargin(0) + self.gridlayout1.setSpacing(6) + self.gridlayout1.setObjectName("gridlayout1") + + self.label_2 = QtGui.QLabel(self.gridLayout_2) + self.label_2.setObjectName("label_2") + self.gridlayout1.addWidget(self.label_2,1,0,1,1) + + self.label_7 = QtGui.QLabel(self.gridLayout_2) + self.label_7.setObjectName("label_7") + self.gridlayout1.addWidget(self.label_7,3,0,1,1) + + self.label = QtGui.QLabel(self.gridLayout_2) + self.label.setMinimumSize(QtCore.QSize(80,0)) + self.label.setObjectName("label") + self.gridlayout1.addWidget(self.label,0,0,1,1) + + self.label_3 = QtGui.QLabel(self.gridLayout_2) + self.label_3.setObjectName("label_3") + self.gridlayout1.addWidget(self.label_3,2,0,1,1) + + self.cb_doc_language = QtGui.QComboBox(self.gridLayout_2) + + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(7),QtGui.QSizePolicy.Policy(0)) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cb_doc_language.sizePolicy().hasHeightForWidth()) + self.cb_doc_language.setSizePolicy(sizePolicy) + self.cb_doc_language.setObjectName("cb_doc_language") + self.gridlayout1.addWidget(self.cb_doc_language,0,1,1,1) + + self.cb_doc_age = QtGui.QComboBox(self.gridLayout_2) + self.cb_doc_age.setObjectName("cb_doc_age") + self.gridlayout1.addWidget(self.cb_doc_age,1,1,1,1) + + self.cb_doc_set = QtGui.QComboBox(self.gridLayout_2) + self.cb_doc_set.setObjectName("cb_doc_set") + self.gridlayout1.addWidget(self.cb_doc_set,2,1,1,1) + + self.cb_doc_element = QtGui.QComboBox(self.gridLayout_2) + self.cb_doc_element.setObjectName("cb_doc_element") + self.gridlayout1.addWidget(self.cb_doc_element,3,1,1,1) + + self.te_doc_view = QtGui.QTextEdit(self.gb_documents) + self.te_doc_view.setGeometry(QtCore.QRect(10,130,411,201)) + self.te_doc_view.setReadOnly(True) + self.te_doc_view.setObjectName("te_doc_view") + self.tabwidget.addTab(self.tab_documents,"") + self.tab_about = QtGui.QWidget() self.tab_about.setObjectName("tab_about") @@ -697,7 +758,7 @@ MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) - self.tabwidget.setCurrentIndex(0) + self.tabwidget.setCurrentIndex(4) QtCore.QObject.connect(self.main_buttonbox,QtCore.SIGNAL("rejected()"),MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -759,6 +820,12 @@ "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal; text-decoration:none;\">\n" "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;\"></p></body></html>", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_ping), QtGui.QApplication.translate("MainWindow", "Servers", None, QtGui.QApplication.UnicodeUTF8)) + self.gb_documents.setTitle(QtGui.QApplication.translate("MainWindow", "Browse in game documents", None, QtGui.QApplication.UnicodeUTF8)) + self.label_2.setText(QtGui.QApplication.translate("MainWindow", "Age", None, QtGui.QApplication.UnicodeUTF8)) + self.label_7.setText(QtGui.QApplication.translate("MainWindow", "Element", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("MainWindow", "Language", None, QtGui.QApplication.UnicodeUTF8)) + self.label_3.setText(QtGui.QApplication.translate("MainWindow", "Set", None, QtGui.QApplication.UnicodeUTF8)) + self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_documents), QtGui.QApplication.translate("MainWindow", "Documents", None, QtGui.QApplication.UnicodeUTF8)) self.label_6.setText(QtGui.QApplication.translate("MainWindow", "pyMoul tools", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_about), QtGui.QApplication.translate("MainWindow", "About", None, QtGui.QApplication.UnicodeUTF8)) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.ui =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-25 15:25:33 UTC (rev 76) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-25 18:50:37 UTC (rev 77) @@ -147,7 +147,7 @@ <enum>QTabWidget::North</enum> </property> <property name="currentIndex" > - <number>0</number> + <number>4</number> </property> <widget class="QWidget" name="tab_graphics" > <attribute name="title" > @@ -1454,6 +1454,110 @@ </widget> </widget> </widget> + <widget class="QWidget" name="tab_documents" > + <attribute name="title" > + <string>Documents</string> + </attribute> + <widget class="QGroupBox" name="gb_documents" > + <property name="geometry" > + <rect> + <x>10</x> + <y>0</y> + <width>431</width> + <height>341</height> + </rect> + </property> + <property name="title" > + <string>Browse in game documents</string> + </property> + <widget class="QWidget" name="gridLayout_2" > + <property name="geometry" > + <rect> + <x>10</x> + <y>20</y> + <width>411</width> + <height>100</height> + </rect> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Age</string> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="label_7" > + <property name="text" > + <string>Element</string> + </property> + </widget> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="minimumSize" > + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="text" > + <string>Language</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="label_3" > + <property name="text" > + <string>Set</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QComboBox" name="cb_doc_language" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QComboBox" name="cb_doc_age" /> + </item> + <item row="2" column="1" > + <widget class="QComboBox" name="cb_doc_set" /> + </item> + <item row="3" column="1" > + <widget class="QComboBox" name="cb_doc_element" /> + </item> + </layout> + </widget> + <widget class="QTextEdit" name="te_doc_view" > + <property name="geometry" > + <rect> + <x>10</x> + <y>130</y> + <width>411</width> + <height>201</height> + </rect> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </widget> + </widget> <widget class="QWidget" name="tab_about" > <attribute name="title" > <string>About</string> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-25 15:25:34
|
Revision: 76 http://pymoul.svn.sourceforge.net/pymoul/?rev=76&view=rev Author: tiran Date: 2007-01-25 07:25:33 -0800 (Thu, 25 Jan 2007) Log Message: ----------- Some logging and Makefile tweaks. Redirect stdout/stderr if sys.frozen Modified Paths: -------------- pymoul/trunk/Makefile pymoul/trunk/setup_win32.py pymoul/trunk/src/moul/log.py Modified: pymoul/trunk/Makefile =================================================================== --- pymoul/trunk/Makefile 2007-01-25 14:21:20 UTC (rev 75) +++ pymoul/trunk/Makefile 2007-01-25 15:25:33 UTC (rev 76) @@ -16,12 +16,18 @@ py2exe: PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) py2exe +innosetup: + PYTHONPATH="src" INNOSETUP="yes" $(PYTHON) setup.py $(SETUPFLAGS) py2exe + bdist_egg: PYTHONPATH="src" $(PYTHON) setup.py $(SETUPFLAGS) bdist_egg run: compileui PYTHONPATH="src" $(PYTHON) src/moul/qt/moulqt.py +runexe: compileui py2exe + dist/moulqt.exe + compileui: $(PYTHON) compileui.py @@ -39,6 +45,8 @@ exe: py2exe +installer: innosetup + egg: bdist_egg doc: doc_html Modified: pymoul/trunk/setup_win32.py =================================================================== --- pymoul/trunk/setup_win32.py 2007-01-25 14:21:20 UTC (rev 75) +++ pymoul/trunk/setup_win32.py 2007-01-25 15:25:33 UTC (rev 76) @@ -71,11 +71,15 @@ pexe['includes'] = ['sip', 'PyQt4', 'encodings', 'encodings.*'] # SSL currently not in use but imported by socket pexe['excludes'] = ['_ssl'] + # added by platform but not yet required + pexe['excludes'].extend(('win32pipe', 'win32api', 'win32con', 'win32evtlog')) + # added by logging.handlers.SMTPHandler but not yet required + pexe['excludes'].append('smtplib') # UPX pexe['upx'] = True pexe['upx_args'] = '--mono --best' # InnoSetup - pexe['innosetup'] = True + pexe['innosetup'] = os.environ.get('INNOSETUP') # TODO: pexe['app_name'] = 'pyMoul' # not required at the moment pexe['includes'].extend(findPyTz()) Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-25 14:21:20 UTC (rev 75) +++ pymoul/trunk/src/moul/log.py 2007-01-25 15:25:33 UTC (rev 76) @@ -37,30 +37,46 @@ # copied from moul.config to prevent circular imports __FROZEN__ = bool(getattr(sys, 'frozen', False)) __LOG_SIGNALS__ = not __FROZEN__ -if __FROZEN__: - level = logging.ERROR -else: - level = logging.DEBUG +class LoggingStdout(object): + """Replacement for stdout/stderr IO + """ + __slot__ = ('_logfunc',) + + def __init__(self, logfunc): + self._logfunc = logfunc + + def write(self, value): + while value.endswith('\n'): + value = value[:-1] + if value: + self._logfunc(value) + format = logging.Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', #'%a, %d %b %Y %H:%M:%S' '%m-%d %H:%M:%S') root = getLogger() -root.setLevel(level) +root.setLevel(logging.DEBUG) -# Add streaming handler for sys.stderr -shdlr = logging.StreamHandler(sys.stderr) -shdlr.setFormatter(format) -shdlr.setLevel(level) -root.addHandler(shdlr) - # setup a memory handler to store records before we have the infrastructure # to log events to a file mhdlr = handlers.MemoryHandler(capacity=16*1024) # MemoryHandler doesn't flush w/o a target mhdlr.setFormatter(format) -mhdlr.setLevel(logging.DEBUG) root.addHandler(mhdlr) +if not __FROZEN__: + # Add streaming handler to sys.stderr. + # Only log to stderr when the program is not frozen! + shdlr = logging.StreamHandler(sys.stderr) + shdlr.setFormatter(format) + root.addHandler(shdlr) +else: + # Redirect stdout and stderr to logger when running as frozen app + sys.stdout = LoggingStdout(getLogger('stdout').info) + print "Stdout redirected" + sys.stderr = LoggingStdout(getLogger('stderr').error) + print >>sys.stderr, "Stderr redirected" + # DEBUG system infos LOG = getLogger('pyMoul') LOG.debug("pyMoul version: %s" % moul_version) @@ -77,11 +93,10 @@ LOG.debug("Adding file logger: %s" % logFile) fhdlr = handlers.RotatingFileHandler(logFile, backupCount=9) fhdlr.setFormatter(format) -fhdlr.setLevel(logging.DEBUG) root.addHandler(fhdlr) fhdlr.doRollover() -# flush and remove remove memory handler +# flush and remove memory handler mhdlr.setTarget(fhdlr) mhdlr.flush() root.removeHandler(mhdlr) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-25 14:21:25
|
Revision: 75 http://pymoul.svn.sourceforge.net/pymoul/?rev=75&view=rev Author: tiran Date: 2007-01-25 06:21:20 -0800 (Thu, 25 Jan 2007) Log Message: ----------- More logging Modified Paths: -------------- pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/win32/__init__.py Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-25 13:50:46 UTC (rev 74) +++ pymoul/trunk/src/moul/log.py 2007-01-25 14:21:20 UTC (rev 75) @@ -23,11 +23,12 @@ __all__ = ['LOG', 'getLogger', 'signalLogDecorator'] +import os +import sys +import platform import logging -from logging import Formatter from logging import handlers -import os -import sys + from moul.metadata import __version__ as moul_version # alias @@ -41,7 +42,7 @@ else: level = logging.DEBUG -format = Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', +format = logging.Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', #'%a, %d %b %Y %H:%M:%S' '%m-%d %H:%M:%S') root = getLogger() @@ -66,6 +67,9 @@ LOG.debug("Python: %s" % repr(sys.version_info)) LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) +LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" + % platform.uname()) +LOG.debug("platform name: %s" % platform.platform(True)) # now get the pymoul userdata dir from moul.config import getPyMoulDataDir Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-25 13:50:46 UTC (rev 74) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-25 14:21:20 UTC (rev 75) @@ -27,7 +27,6 @@ from moul.osdependent.win32.winpath import get_homedir from moul.osdependent.win32.winpath import get_appdata - MOUL_DIR = "Uru Live" EXEC_NAME = "UruLauncher.exe" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |