[Pymoul-svn] SF.net SVN: pymoul: [79] pymoul/trunk/src/moul
Status: Alpha
Brought to you by:
tiran
|
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.
|