SF.net SVN: jython:[7186] trunk/jython

[email protected] Fri, 21 Jan 2011 01:18:35 +0000
Newsgroups gmane.comp.lang.jython.cvs
Message-ID <[email protected]>
Revision: 7186
          http://jython.svn.sourceforge.net/jython/?rev=7186&view=rev
Author:   pjenvey
Date:     2011-01-21 01:18:35 +0000 (Fri, 21 Jan 2011)

Log Message:
-----------
o fix threading.local subclassing problems with __init__ arguments
o fastGetDict doesn't need to synchronize around a ThreadLocal initialization
fixes #1667
thanks Kelly Campbell

Modified Paths:
--------------
    trunk/jython/NEWS
    trunk/jython/src/org/python/modules/thread/PyLocal.java

Added Paths:
-----------
    trunk/jython/Lib/test/test_threading_local_jy.py

Added: trunk/jython/Lib/test/test_threading_local_jy.py
===================================================================
--- trunk/jython/Lib/test/test_threading_local_jy.py	                        (rev 0)
+++ trunk/jython/Lib/test/test_threading_local_jy.py	2011-01-21 01:18:35 UTC (rev 7186)
@@ -0,0 +1,61 @@
+"""Test for thread locals"""
+import random
+import sys
+import threading
+import time
+import unittest
+from test import test_support
+from threading import local
+
+class LocalStuff(local):
+    def __init__(self, stuff, foo=1):
+        local.__init__(self)
+        self.stuff = stuff
+        self.foo = foo
+
+class TestThread(threading.Thread):
+    def __init__(self, stuff, name):
+        threading.Thread.__init__(self)
+        self.stuff = stuff
+        self.name = name
+        self.errors = []
+
+    def run(self):
+        for i in xrange(10):
+            try:
+                self.stuff.stuff = self.name
+                myStuff = self.stuff.stuff
+                time.sleep(random.random() * 2)
+                if myStuff != self.stuff.stuff:
+                    self.errors.append("myStuff should equal self.stuff.stuff")
+                if self.stuff.foo != 1:
+                    self.errors.append("foo should be 1")
+            except TypeError, te:
+                self.errors.append("TypeError: %s" % te)
+            except:
+                self.errors.append("unexpected error: %s" % sys.exc_info()[0] )
+
+    def getErrors(self):
+        return self.errors
+
+class ThreadLocalConstructorTestCase(unittest.TestCase):
+
+    def test_construct_locals(self):
+        """Ensures that constructing a local can have arguments"""
+        stuff = LocalStuff("main stuff")
+        threads = []
+        for i in xrange(20):
+            threads.append(TestThread(stuff, name=("thread-%d" % i)))
+            threads[i].start()
+        for i in xrange(20):
+            threads[i].join()
+            errors = threads[i].getErrors()
+            self.assertEquals(0, len(errors), errors)
+
+
+def test_main():
+    test_support.run_unittest(ThreadLocalConstructorTestCase)
+
+
+if __name__ == "__main__":
+    test_main()

Modified: trunk/jython/NEWS
===================================================================
--- trunk/jython/NEWS	2011-01-10 23:29:19 UTC (rev 7185)
+++ trunk/jython/NEWS	2011-01-21 01:18:35 UTC (rev 7186)
@@ -1,5 +1,9 @@
 Jython NEWS
 
+Jython 2.5.2
+  Bugs Fixed
+    - [ 1667 ] thread.local subclasses with constructor params fail
+
 Jython 2.5.2rc3
   Bugs Fixed
     - [ 1674 ] PDB crashes under the JSR-223 scripting engine

Modified: trunk/jython/src/org/python/modules/thread/PyLocal.java
===================================================================
--- trunk/jython/src/org/python/modules/thread/PyLocal.java	2011-01-10 23:29:19 UTC (rev 7185)
+++ trunk/jython/src/org/python/modules/thread/PyLocal.java	2011-01-21 01:18:35 UTC (rev 7186)
@@ -1,3 +1,4 @@
+/* Copyright (c) Jython Developers */
 package org.python.modules.thread;
 
 import org.python.core.Py;
@@ -6,7 +7,6 @@
 import org.python.core.PyObject;
 import org.python.core.PyType;
 import org.python.expose.ExposedGet;
-import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedSet;
 import org.python.expose.ExposedType;
@@ -28,9 +28,8 @@
 
     public PyLocal(PyType subType) {
         super(subType);
-        // Because the instantiation of a type instance in PyType.invoke_new_
-        // calls dispatch__init__, we call tdict.set here so dispatch__init__
-        // doesn't get called a second time for a thread in fastGetDict
+        // Don't lazy load the underlying dict in the insantiating thread; that would call
+        // __init__ a the second time
         tdict.set(new PyDictionary());
     }
 
@@ -40,29 +39,24 @@
                                         PyType subtype,
                                         PyObject[] args,
                                         String[] keywords) {
+        PyObject[] where = new PyObject[1];
+        subtype.lookup_where("__init__", where);
+        if (where[0] == PyObject.TYPE && args.length > 0) {
+            throw Py.TypeError("Initialization arguments are not supported");
+        }
+
         PyLocal newobj;
         if (new_.getWrappedType() == subtype) {
             newobj = new PyLocal();
         } else {
             newobj = new PyLocalDerived(subtype);
         }
-        if (init) {
-            newobj._local___init__(args, keywords);
-        }
+        newobj.args = args;
+        newobj.keywords = keywords;
+
         return newobj;
     }
 
-    @ExposedMethod
-    final void _local___init__(PyObject[] args, String[] keywords) {
-        PyObject[] where = new PyObject[1];
-        getType().lookup_where("__init__", where);
-        if (where[0] == TYPE && args.length > 0) {
-            throw Py.TypeError("Initialization arguments are not supported");
-        }
-        this.args = args;
-        this.keywords = keywords;
-    }
-
     @Override
     @ExposedGet(name = "__dict__")
     public PyObject getDict() {
@@ -76,7 +70,7 @@
     }
 
     @Override
-    public synchronized PyObject fastGetDict() {
+    public PyObject fastGetDict() {
         PyDictionary ldict = tdict.get();
         if (ldict == null) {
             ldict = new PyDictionary();


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

------------------------------------------------------------------------------
Special Offer-- Download ArcSight Logger for FREE (a $49 USD value)!
Finally, a world-class log management solution at an even better price-free!
Download using promo code Free_Logger_4_Dev2Dev. Offer expires 
February 28th, so secure your free ArcSight Logger TODAY! 
http://p.sf.net/sfu/arcsight-sfd2d