[Erp5-report] r15061 - /erp5/trunk/utils/oood/
nobody at svn.erp5.org
nobody at svn.erp5.org
Fri Jun 29 10:39:41 CEST 2007
Author: kazuhiko
Date: Fri Jun 29 10:39:40 2007
New Revision: 15061
URL: http://svn.erp5.org?rev=15061&view=rev
Log:
revise for python-2.3 compatibility.
Added:
erp5/trunk/utils/oood/_threading_local.py
Modified:
erp5/trunk/utils/oood/dispatcher.py
erp5/trunk/utils/oood/logger.py
erp5/trunk/utils/oood/oood_common.py
Added: erp5/trunk/utils/oood/_threading_local.py
URL: http://svn.erp5.org/erp5/trunk/utils/oood/_threading_local.py?rev=15061&view=auto
==============================================================================
--- erp5/trunk/utils/oood/_threading_local.py (added)
+++ erp5/trunk/utils/oood/_threading_local.py Fri Jun 29 10:39:40 2007
@@ -1,0 +1,237 @@
+"""Thread-local objects
+
+(Note that this module provides a Python version of thread
+ threading.local class. Depending on the version of Python you're
+ using, there may be a faster one available. You should always import
+ the local class from threading.)
+
+Thread-local objects support the management of thread-local data.
+If you have data that you want to be local to a thread, simply create
+a thread-local object and use its attributes:
+
+ >>> mydata = local()
+ >>> mydata.number = 42
+ >>> mydata.number
+ 42
+
+You can also access the local-object's dictionary:
+
+ >>> mydata.__dict__
+ {'number': 42}
+ >>> mydata.__dict__.setdefault('widgets', [])
+ []
+ >>> mydata.widgets
+ []
+
+What's important about thread-local objects is that their data are
+local to a thread. If we access the data in a different thread:
+
+ >>> log = []
+ >>> def f():
+ ... items = mydata.__dict__.items()
+ ... items.sort()
+ ... log.append(items)
+ ... mydata.number = 11
+ ... log.append(mydata.number)
+
+ >>> import threading
+ >>> thread = threading.Thread(target=f)
+ >>> thread.start()
+ >>> thread.join()
+ >>> log
+ [[], 11]
+
+we get different data. Furthermore, changes made in the other thread
+don't affect data seen in this thread:
+
+ >>> mydata.number
+ 42
+
+Of course, values you get from a local object, including a __dict__
+attribute, are for whatever thread was current at the time the
+attribute was read. For that reason, you generally don't want to save
+these values across threads, as they apply only to the thread they
+came from.
+
+You can create custom local objects by subclassing the local class:
+
+ >>> class MyLocal(local):
+ ... number = 2
+ ... initialized = False
+ ... def __init__(self, **kw):
+ ... if self.initialized:
+ ... raise SystemError('__init__ called too many times')
+ ... self.initialized = True
+ ... self.__dict__.update(kw)
+ ... def squared(self):
+ ... return self.number ** 2
+
+This can be useful to support default values, methods and
+initialization. Note that if you define an __init__ method, it will be
+called each time the local object is used in a separate thread. This
+is necessary to initialize each thread's dictionary.
+
+Now if we create a local object:
+
+ >>> mydata = MyLocal(color='red')
+
+Now we have a default number:
+
+ >>> mydata.number
+ 2
+
+an initial color:
+
+ >>> mydata.color
+ 'red'
+ >>> del mydata.color
+
+And a method that operates on the data:
+
+ >>> mydata.squared()
+ 4
+
+As before, we can access the data in a separate thread:
+
+ >>> log = []
+ >>> thread = threading.Thread(target=f)
+ >>> thread.start()
+ >>> thread.join()
+ >>> log
+ [[('color', 'red'), ('initialized', True)], 11]
+
+without affecting this thread's data:
+
+ >>> mydata.number
+ 2
+ >>> mydata.color
+ Traceback (most recent call last):
+ ...
+ AttributeError: 'MyLocal' object has no attribute 'color'
+
+Note that subclasses can define slots, but they are not thread
+local. They are shared across threads:
+
+ >>> class MyLocal(local):
+ ... __slots__ = 'number'
+
+ >>> mydata = MyLocal()
+ >>> mydata.number = 42
+ >>> mydata.color = 'red'
+
+So, the separate thread:
+
+ >>> thread = threading.Thread(target=f)
+ >>> thread.start()
+ >>> thread.join()
+
+affects what we see:
+
+ >>> mydata.number
+ 11
+
+>>> del mydata
+"""
+
+# Threading import is at end
+
+class _localbase(object):
+ __slots__ = '_local__key', '_local__args', '_local__lock'
+
+ def __new__(cls, *args, **kw):
+ self = object.__new__(cls)
+ key = '_local__key', 'thread.local.' + str(id(self))
+ object.__setattr__(self, '_local__key', key)
+ object.__setattr__(self, '_local__args', (args, kw))
+ object.__setattr__(self, '_local__lock', RLock())
+
+ if args or kw and (cls.__init__ is object.__init__):
+ raise TypeError("Initialization arguments are not supported")
+
+ # We need to create the thread dict in anticipation of
+ # __init__ being called, to make sire we don't cal it
+ # again ourselves.
+ dict = object.__getattribute__(self, '__dict__')
+ currentThread().__dict__[key] = dict
+
+ return self
+
+def _patch(self):
+ key = object.__getattribute__(self, '_local__key')
+ d = currentThread().__dict__.get(key)
+ if d is None:
+ d = {}
+ currentThread().__dict__[key] = d
+ object.__setattr__(self, '__dict__', d)
+
+ # we have a new instance dict, so call out __init__ if we have
+ # one
+ cls = type(self)
+ if cls.__init__ is not object.__init__:
+ args, kw = object.__getattribute__(self, '_local__args')
+ cls.__init__(self, *args, **kw)
+ else:
+ object.__setattr__(self, '__dict__', d)
+
+class local(_localbase):
+
+ def __getattribute__(self, name):
+ lock = object.__getattribute__(self, '_local__lock')
+ lock.acquire()
+ try:
+ _patch(self)
+ return object.__getattribute__(self, name)
+ finally:
+ lock.release()
+
+ def __setattr__(self, name, value):
+ lock = object.__getattribute__(self, '_local__lock')
+ lock.acquire()
+ try:
+ _patch(self)
+ return object.__setattr__(self, name, value)
+ finally:
+ lock.release()
+
+ def __delattr__(self, name):
+ lock = object.__getattribute__(self, '_local__lock')
+ lock.acquire()
+ try:
+ _patch(self)
+ return object.__delattr__(self, name)
+ finally:
+ lock.release()
+
+
+ def __del__():
+ threading_enumerate = enumerate
+ __getattribute__ = object.__getattribute__
+
+ def __del__(self):
+ key = __getattribute__(self, '_local__key')
+
+ try:
+ threads = list(threading_enumerate())
+ except:
+ # if enumerate fails, as it seems to do during
+ # shutdown, we'll skip cleanup under the assumption
+ # that there is nothing to clean up
+ return
+
+ for thread in threads:
+ try:
+ __dict__ = thread.__dict__
+ except AttributeError:
+ # Thread is dying, rest in peace
+ continue
+
+ if key in __dict__:
+ try:
+ del __dict__[key]
+ except KeyError:
+ pass # didn't have anything in this thread
+
+ return __del__
+ __del__ = __del__()
+
+from threading import currentThread, enumerate, RLock
Modified: erp5/trunk/utils/oood/dispatcher.py
URL: http://svn.erp5.org/erp5/trunk/utils/oood/dispatcher.py?rev=15061&r1=15060&r2=15061&view=diff
==============================================================================
--- erp5/trunk/utils/oood/dispatcher.py (original)
+++ erp5/trunk/utils/oood/dispatcher.py Fri Jun 29 10:39:40 2007
@@ -43,6 +43,13 @@
import time
import traceback
import zipfile
+import shutil
+
+# for python-2.3
+if getattr(threading, 'local', None) is None:
+ from _threading_local import local
+ threading.local = local
+
from SimpleXMLRPCServer import *
from SocketServer import ThreadingMixIn
@@ -446,7 +453,10 @@
pth = os.path.join(config.oood_home, self.tmp_dir_name, os.path.basename(filename))
for f in glob.glob('%s/*'%self.tmp_dir_name):
if not config.debug_mode:
- os.remove(f)
+ if os.path.isdir(f):
+ shutil.rmtree(f)
+ else:
+ os.remove(f)
any = True
#if not any:
#Log.warning('no file beginning with %s' % filename)
Modified: erp5/trunk/utils/oood/logger.py
URL: http://svn.erp5.org/erp5/trunk/utils/oood/logger.py?rev=15061&r1=15060&r2=15061&view=diff
==============================================================================
--- erp5/trunk/utils/oood/logger.py (original)
+++ erp5/trunk/utils/oood/logger.py Fri Jun 29 10:39:40 2007
@@ -36,20 +36,21 @@
import lib
-logging.basicConfig(level=config.log_level,
- format='%(asctime)s %(levelname)-8s %(message)s',
- datefmt='%Y/%m/%d %H:%M:%S',
- filename=config.log_file,
- filemode='a')
-
-
class mylog(object):
funcs = ('debug', 'info', 'warning', 'error', 'critical', 'exception')
def __init__(self):
+ self.logger = logging.getLogger('oood')
+ handler = logging.FileHandler(config.log_file)
+ formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s',
+ '%Y/%m/%d %H:%M:%S')
+ handler.setFormatter(formatter)
+ self.logger.addHandler(handler)
+ self.logger.setLevel(config.log_level)
+
def mkFunc(f):
- logfunc = getattr(logging, f)
+ logfunc = getattr(self.logger, f)
def _func(msg, *a, **kw):
thread_name = threading.currentThread().getName()
msg = '<%s> %s' %(thread_name, msg)
Modified: erp5/trunk/utils/oood/oood_common.py
URL: http://svn.erp5.org/erp5/trunk/utils/oood/oood_common.py?rev=15061&r1=15060&r2=15061&view=diff
==============================================================================
--- erp5/trunk/utils/oood/oood_common.py (original)
+++ erp5/trunk/utils/oood/oood_common.py Fri Jun 29 10:39:40 2007
@@ -101,35 +101,35 @@
return func(self, *args, **kwargs)
return wrappedFunc
- @isCodeValid
def isOk(self):
"""
Check if the response is "OK".
"""
return self.code == 200
-
- @isCodeValid
+ isOk = isCodeValid(isOk)
+
def isError(self):
"""
Check if the response signals an error.
"""
return self.code != 200
-
- @isCodeValid
+ isError = isCodeValid(isError)
+
def isClientError(self):
"""
Check if the error was caused by client, or was it an
internal problem of the server.
"""
return self.code > 400 and self.code < 500
-
- @isCodeValid
+ isClientError = isCodeValid(isClientError)
+
def isServerError(self):
"""
Check if the error was caused by client, or was it an
internal problem of the server.
"""
return self.code > 500
+ isServerError = isCodeValid(isServerError)
def responseFactory(response):
"""
More information about the Erp5-report
mailing list