[Jython-checkins] jython: Now uses java.util.WeakHashMap to back weakref.WeakSet

jim.baker jython-checkins at python.org
Fri Nov 21 03:18:25 CET 2014


https://hg.python.org/jython/rev/f51940218cf2
changeset:   7420:f51940218cf2
user:        Jim Baker <jim.baker at rackspace.com>
date:        Thu Nov 20 19:17:46 2014 -0700
summary:
  Now uses java.util.WeakHashMap to back weakref.WeakSet

Adds jythonlib.set_builder so that Python sets/derived sets can be
built with an arbitrary backing java.util.Set.  Updates test_weakset
to 2.7 and fixes all outstanding skips. Updates gderived.py so that it
can include arbitrary additional imports, based on a new import
directive.

files:
  Lib/_weakrefset.py                                 |  213 +---------
  Lib/test/test_set.py                               |    3 +-
  Lib/test/test_weakset.py                           |   71 ++-
  src/org/python/core/BaseSet.java                   |    8 +-
  src/org/python/core/PyDictionaryDerived.java       |   18 +-
  src/org/python/core/PySet.java                     |    9 +
  src/org/python/core/PySetDerived.java              |   10 +
  src/org/python/modules/_jythonlib/_jythonlib.java  |    2 +
  src/org/python/modules/_jythonlib/set_builder.java |   48 ++
  src/templates/dict.derived                         |   10 +
  src/templates/gderived.py                          |   25 +
  src/templates/set.derived                          |   11 +
  12 files changed, 186 insertions(+), 242 deletions(-)


diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py
--- a/Lib/_weakrefset.py
+++ b/Lib/_weakrefset.py
@@ -2,211 +2,20 @@
 # This code is separated-out because it is needed
 # by abc.py to load everything else at startup.
 
-from _weakref import ref
+from java.util import WeakHashMap
+from java.util.Collections import newSetFromMap, synchronizedMap
+from jythonlib import set_builder, MapMaker
 
 __all__ = ['WeakSet']
 
 
-class _IterationGuard(object):
-    # This context manager registers itself in the current iterators of the
-    # weak container, such as to delay all removals until the context manager
-    # exits.
-    # This technique should be relatively thread-safe (since sets are).
+class WeakSet(set):
 
-    def __init__(self, weakcontainer):
-        # Don't create cycles
-        self.weakcontainer = ref(weakcontainer)
+    def __new__(cls, data=None):
+        def _build():
+            # Although not specified in the docs, WeakSet supports equality on
+            # keys, as seen in test_weakset and its use of testing class
+            # SomeClass. Therefore we cannot use MapMaker in this case.
+            return newSetFromMap(synchronizedMap(WeakHashMap()))
 
-    def __enter__(self):
-        w = self.weakcontainer()
-        if w is not None:
-            w._iterating.add(self)
-        return self
-
-    def __exit__(self, e, t, b):
-        w = self.weakcontainer()
-        if w is not None:
-            s = w._iterating
-            s.remove(self)
-            if not s:
-                w._commit_removals()
-
-
-class WeakSet(object):
-    def __init__(self, data=None):
-        self.data = set()
-        def _remove(item, selfref=ref(self)):
-            self = selfref()
-            if self is not None:
-                if self._iterating:
-                    self._pending_removals.append(item)
-                else:
-                    self.data.discard(item)
-        self._remove = _remove
-        # A list of keys to be removed
-        self._pending_removals = []
-        self._iterating = set()
-        if data is not None:
-            self.update(data)
-
-    def _commit_removals(self):
-        l = self._pending_removals
-        discard = self.data.discard
-        while l:
-            discard(l.pop())
-
-    def __iter__(self):
-        with _IterationGuard(self):
-            for itemref in self.data:
-                item = itemref()
-                if item is not None:
-                    yield item
-
-    def __len__(self):
-        return sum(x() is not None for x in self.data)
-
-    def __contains__(self, item):
-        return ref(item) in self.data
-
-    def __reduce__(self):
-        return (self.__class__, (list(self),),
-                getattr(self, '__dict__', None))
-
-    __hash__ = None
-
-    def add(self, item):
-        if self._pending_removals:
-            self._commit_removals()
-        self.data.add(ref(item, self._remove))
-
-    def clear(self):
-        if self._pending_removals:
-            self._commit_removals()
-        self.data.clear()
-
-    def copy(self):
-        return self.__class__(self)
-
-    def pop(self):
-        if self._pending_removals:
-            self._commit_removals()
-        while True:
-            try:
-                itemref = self.data.pop()
-            except KeyError:
-                raise KeyError('pop from empty WeakSet')
-            item = itemref()
-            if item is not None:
-                return item
-
-    def remove(self, item):
-        if self._pending_removals:
-            self._commit_removals()
-        self.data.remove(ref(item))
-
-    def discard(self, item):
-        if self._pending_removals:
-            self._commit_removals()
-        self.data.discard(ref(item))
-
-    def update(self, other):
-        if self._pending_removals:
-            self._commit_removals()
-        if isinstance(other, self.__class__):
-            self.data.update(other.data)
-        else:
-            for element in other:
-                self.add(element)
-
-    def __ior__(self, other):
-        self.update(other)
-        return self
-
-    # Helper functions for simple delegating methods.
-    def _apply(self, other, method):
-        if not isinstance(other, self.__class__):
-            other = self.__class__(other)
-        newdata = method(other.data)
-        newset = self.__class__()
-        newset.data = newdata
-        return newset
-
-    def difference(self, other):
-        return self._apply(other, self.data.difference)
-    __sub__ = difference
-
-    def difference_update(self, other):
-        if self._pending_removals:
-            self._commit_removals()
-        if self is other:
-            self.data.clear()
-        else:
-            self.data.difference_update(ref(item) for item in other)
-    def __isub__(self, other):
-        if self._pending_removals:
-            self._commit_removals()
-        if self is other:
-            self.data.clear()
-        else:
-            self.data.difference_update(ref(item) for item in other)
-        return self
-
-    def intersection(self, other):
-        return self._apply(other, self.data.intersection)
-    __and__ = intersection
-
-    def intersection_update(self, other):
-        if self._pending_removals:
-            self._commit_removals()
-        self.data.intersection_update(ref(item) for item in other)
-    def __iand__(self, other):
-        if self._pending_removals:
-            self._commit_removals()
-        self.data.intersection_update(ref(item) for item in other)
-        return self
-
-    def issubset(self, other):
-        return self.data.issubset(ref(item) for item in other)
-    __lt__ = issubset
-
-    def __le__(self, other):
-        return self.data <= set(ref(item) for item in other)
-
-    def issuperset(self, other):
-        return self.data.issuperset(ref(item) for item in other)
-    __gt__ = issuperset
-
-    def __ge__(self, other):
-        return self.data >= set(ref(item) for item in other)
-
-    def __eq__(self, other):
-        if not isinstance(other, self.__class__):
-            return NotImplemented
-        return self.data == set(ref(item) for item in other)
-
-    def symmetric_difference(self, other):
-        return self._apply(other, self.data.symmetric_difference)
-    __xor__ = symmetric_difference
-
-    def symmetric_difference_update(self, other):
-        if self._pending_removals:
-            self._commit_removals()
-        if self is other:
-            self.data.clear()
-        else:
-            self.data.symmetric_difference_update(ref(item) for item in other)
-    def __ixor__(self, other):
-        if self._pending_removals:
-            self._commit_removals()
-        if self is other:
-            self.data.clear()
-        else:
-            self.data.symmetric_difference_update(ref(item) for item in other)
-        return self
-
-    def union(self, other):
-        return self._apply(other, self.data.union)
-    __or__ = union
-
-    def isdisjoint(self, other):
-        return len(self.intersection(other)) == 0
+        return set_builder(_build, cls)(data)
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -310,7 +310,7 @@
             fo.close()
             test_support.unlink(test_support.TESTFN)
 
-    @unittest.skipIf(test_support.is_jython, "FIXME: Not yet sure how to fix this")
+    @unittest.skipIf(test_support.is_jython, "Not meaningful for Jython")
     def test_do_not_rehash_dict_keys(self):
         n = 10
         d = dict.fromkeys(map(HashCountingInt, xrange(n)))
@@ -917,6 +917,7 @@
         set('abc')
         set(gooditer())
 
+    @unittest.skipIf(test_support.is_jython, "Jython provides stronger support for concurrent updates")
     def test_changingSizeWhileIterating(self):
         s = set([1,2,3])
         try:
diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py
--- a/Lib/test/test_weakset.py
+++ b/Lib/test/test_weakset.py
@@ -1,5 +1,18 @@
+# Jython specific notes:
+#
+# 1. Deletion (del) or reliance on going out of scope must be followed
+#    by a gc.collect(); use extra_collect() if a callback will be
+#    tested as well.
+#
+# 2. Avoid eventual consistency issues in the length computation by
+#    computing the len of the list of the WeakSet
+#
+# 3. Jython can weakly refer to any object, unlike CPython, so don't
+#    test for nonexistent TypeErrors
+
 import unittest
 from test import test_support
+from test.test_weakref import extra_collect
 from weakref import proxy, ref, WeakSet
 import operator
 import copy
@@ -30,6 +43,9 @@
     def __hash__(self):
         return hash((SomeClass, self.value))
 
+    def __repr__(self):
+        return "SC(%s,%s)" % (self.value, id(self.value))
+
 class RefCycle(object):
     def __init__(self):
         self.cycle = self
@@ -63,14 +79,13 @@
     def test_new_or_init(self):
         self.assertRaises(TypeError, WeakSet, [], 2)
 
-    #@unittest.skipIf(test_support.is_jython, "FIXME: not working in Jython")
     def test_len(self):
         self.assertEqual(len(self.s), len(self.d))
         self.assertEqual(len(self.fs), 1)
         del self.obj
+        gc.collect()
         self.assertEqual(len(self.fs), 0)
 
-    #@unittest.skipIf(test_support.is_jython, "FIXME: not working in Jython")
     def test_contains(self):
         for c in self.letters:
             self.assertEqual(c in self.s, c in self.d)
@@ -78,6 +93,7 @@
         self.assertNotIn(1, self.s)
         self.assertIn(self.obj, self.fs)
         del self.obj
+        gc.collect()
         self.assertNotIn(SomeClass('F'), self.fs)
 
     def test_union(self):
@@ -92,10 +108,11 @@
             c = C(self.items2)
             self.assertEqual(self.s.union(c), x)
             del c
-        self.assertEqual(len(u), len(self.items) + len(self.items2))
+            gc.collect()
+        self.assertEqual(len(list(u)), len(list(self.items)) + len(list(self.items2)))
         self.items2.pop()
         gc.collect()
-        self.assertEqual(len(u), len(self.items) + len(self.items2))
+        self.assertEqual(len(list(u)), len(list(self.items)) + len(list(self.items2)))
 
     def test_or(self):
         i = self.s.union(self.items2)
@@ -115,7 +132,7 @@
         self.assertEqual(len(i), len(self.items2))
         self.items2.pop()
         gc.collect()
-        self.assertEqual(len(i), len(self.items2))
+        self.assertEqual(len(list(i)), len(list(self.items2)))
 
     def test_isdisjoint(self):
         self.assertTrue(self.s.isdisjoint(WeakSet(self.items2)))
@@ -149,7 +166,7 @@
         self.assertEqual(len(i), len(self.items) + len(self.items2))
         self.items2.pop()
         gc.collect()
-        self.assertEqual(len(i), len(self.items) + len(self.items2))
+        self.assertEqual(len(list(i)), len(list(self.items)) + len(list(self.items2)))
 
     def test_xor(self):
         i = self.s.symmetric_difference(self.items2)
@@ -167,14 +184,12 @@
         self.assertFalse(set('a').issubset('cbs'))
         self.assertFalse(set('cbs').issuperset('a'))
 
-    #@unittest.skipIf(test_support.is_jython, "FIXME: not working in Jython")
     def test_lt(self):
         self.assertTrue(self.ab_weakset < self.abcde_weakset)
         self.assertFalse(self.abcde_weakset < self.def_weakset)
         self.assertFalse(self.ab_weakset < self.ab_weakset)
         self.assertFalse(WeakSet() < WeakSet())
 
-    #@unittest.skipIf(test_support.is_jython, "FIXME: not working in Jython")
     def test_gt(self):
         self.assertTrue(self.abcde_weakset > self.ab_weakset)
         self.assertFalse(self.abcde_weakset > self.def_weakset)
@@ -229,7 +244,6 @@
         self.assertEqual(self.s, dup)
         self.assertNotEqual(id(self.s), id(dup))
 
-    #@unittest.skipIf(test_support.is_jython, "FIXME: not working in Jython")
     def test_add(self):
         x = SomeClass('Q')
         self.s.add(x)
@@ -237,25 +251,29 @@
         dup = self.s.copy()
         self.s.add(x)
         self.assertEqual(self.s, dup)
-        self.assertRaises(TypeError, self.s.add, [])
+        if not test_support.is_jython:  # Jython/JVM can weakly reference list and other objects
+            self.assertRaises(TypeError, self.s.add, [])
         self.fs.add(Foo())
-        self.assertTrue(len(self.fs) == 1)
+        gc.collect()  # CPython assumes Foo() went out of scope and was collected, so ensure the same
+        self.assertEqual(len(list(self.fs)), 1)
         self.fs.add(self.obj)
-        self.assertTrue(len(self.fs) == 1)
+        self.assertEqual(len(list(self.fs)), 1)
 
     def test_remove(self):
         x = SomeClass('a')
         self.s.remove(x)
         self.assertNotIn(x, self.s)
         self.assertRaises(KeyError, self.s.remove, x)
-        self.assertRaises(TypeError, self.s.remove, [])
+        if not test_support.is_jython:  # Jython/JVM can weakly reference list and other objects
+            self.assertRaises(TypeError, self.s.remove, [])
 
     def test_discard(self):
         a, q = SomeClass('a'), SomeClass('Q')
         self.s.discard(a)
         self.assertNotIn(a, self.s)
         self.s.discard(q)
-        self.assertRaises(TypeError, self.s.discard, [])
+        if not test_support.is_jython:  # Jython/JVM can weakly reference list and other objects
+            self.assertRaises(TypeError, self.s.discard, [])
 
     def test_pop(self):
         for i in range(len(self.s)):
@@ -306,8 +324,9 @@
                 self.assertIn(c, self.s)
             else:
                 self.assertNotIn(c, self.s)
-        self.assertRaises(TypeError, self.s.difference_update, [[]])
-        self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
+        if not test_support.is_jython:  # Jython/JVM can weakly reference list and other objects
+            self.assertRaises(TypeError, self.s.difference_update, [[]])
+            self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
 
     def test_isub(self):
         self.s -= set(self.items2)
@@ -348,15 +367,17 @@
         self.assertEqual(t, WeakSet())
 
     def test_eq(self):
-        # issue 5964
-        self.assertTrue(self.s == self.s)
-        self.assertTrue(self.s == WeakSet(self.items))
-        self.assertFalse(self.s == set(self.items))
-        self.assertFalse(self.s == list(self.items))
-        self.assertFalse(self.s == tuple(self.items))
-        self.assertFalse(self.s == 1)
+        # issue 5964 (http://bugs.python.org/issue5964)
+        self.assertEqual(self.s, self.s)
+        self.assertEqual(self.s, WeakSet(self.items))
+        # Jython diverges here in the next test because it constructs
+        # WeakSet as a subclass of set; this seems to be the proper
+        # thing to do given what is the typical comparison
+        self.assertEqual(self.s, set(self.items))
+        self.assertNotEqual(self.s, list(self.items))
+        self.assertNotEqual(self.s, tuple(self.items))
+        self.assertNotEqual(self.s, 1)
 
-    #@unittest.skipIf(test_support.is_jython, "FIXME: not working in Jython")
     def test_weak_destroy_while_iterating(self):
         # Issue #7105: iterators shouldn't crash when a key is implicitly removed
         # Create new items to be sure no-one else holds a reference
@@ -370,6 +391,7 @@
         # We have removed either the first consumed items, or another one
         self.assertIn(len(list(it)), [len(items), len(items) - 1])
         del it
+        gc.collect()
         # The removal has been committed
         self.assertEqual(len(s), len(items))
 
@@ -410,6 +432,7 @@
         items = [RefCycle() for i in range(N)]
         s = WeakSet(items)
         del items
+        gc.collect()
         it = iter(s)
         try:
             next(it)
diff --git a/src/org/python/core/BaseSet.java b/src/org/python/core/BaseSet.java
--- a/src/org/python/core/BaseSet.java
+++ b/src/org/python/core/BaseSet.java
@@ -231,9 +231,6 @@
 
             @Override
             public PyObject __iternext__() {
-                if (size != size()) {
-                    throw Py.RuntimeError("set changed size during iteration");
-                }
                 if (iterator.hasNext()) {
                     return iterator.next();
                 }
@@ -481,7 +478,7 @@
     }
 
     /**
-     * Create a new <et of type from iterable.
+     * Create a new set of type from iterable.
      *
      * @param type a set type
      * @param iterable an iterable or null
@@ -494,8 +491,7 @@
         } else if (type == PyFrozenSet.TYPE) {
             so = new PyFrozenSet(iterable);
         } else if (Py.isSubClass(type, PySet.TYPE)) {
-            so = new PySetDerived(type);
-            so._update(iterable);
+            so = (BaseSet)(type.__call__(iterable == null ? Py.EmptyTuple : iterable));
         } else {
             so = new PyFrozenSetDerived(type, iterable);
         }
diff --git a/src/org/python/core/PyDictionaryDerived.java b/src/org/python/core/PyDictionaryDerived.java
--- a/src/org/python/core/PyDictionaryDerived.java
+++ b/src/org/python/core/PyDictionaryDerived.java
@@ -67,15 +67,6 @@
         }
     }
 
-    public PyDictionaryDerived(PyType subtype, ConcurrentMap<PyObject, PyObject> backingMap, boolean useBackingMap) {
-        super(subtype, backingMap, useBackingMap);
-        slots=new PyObject[subtype.getNumSlots()];
-        dict=subtype.instDict();
-        if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
-        }
-    }
-
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
@@ -1149,6 +1140,15 @@
         return super.__coerce_ex__(o);
     }
 
+    public PyDictionaryDerived(PyType subtype,ConcurrentMap backingMap,boolean useBackingMap) {
+        super(subtype,backingMap,useBackingMap);
+        slots=new PyObject[subtype.getNumSlots()];
+        dict=subtype.instDict();
+        if (subtype.needsFinalizer()) {
+            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        }
+    }
+
     public String toString() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__repr__");
diff --git a/src/org/python/core/PySet.java b/src/org/python/core/PySet.java
--- a/src/org/python/core/PySet.java
+++ b/src/org/python/core/PySet.java
@@ -2,6 +2,7 @@
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Set;
 
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -34,6 +35,14 @@
         super(TYPE, _update(Generic.<PyObject>concurrentSet(), data));
     }
 
+    public PySet(Set backing_set, PyObject data) {
+        super(TYPE, _update(backing_set, data));
+    }
+
+    public PySet(PyType type, Set backing_set, PyObject data) {
+        super(type, _update(backing_set, data));
+    }
+
     @ExposedNew
     @ExposedMethod(doc = BuiltinDocs.set___init___doc)
     final void set___init__(PyObject[] args, String[] kwds) {
diff --git a/src/org/python/core/PySetDerived.java b/src/org/python/core/PySetDerived.java
--- a/src/org/python/core/PySetDerived.java
+++ b/src/org/python/core/PySetDerived.java
@@ -1,6 +1,7 @@
 /* Generated file, do not modify.  See jython/src/templates/gderived.py. */
 package org.python.core;
 
+import java.util.Set;
 import java.io.Serializable;
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
@@ -1139,6 +1140,15 @@
         return super.__coerce_ex__(o);
     }
 
+    public PySetDerived(PyType subtype,Set backing_set,PyObject data) {
+        super(subtype,backing_set,data);
+        slots=new PyObject[subtype.getNumSlots()];
+        dict=subtype.instDict();
+        if (subtype.needsFinalizer()) {
+            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        }
+    }
+
     public String toString() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__repr__");
diff --git a/src/org/python/modules/_jythonlib/_jythonlib.java b/src/org/python/modules/_jythonlib/_jythonlib.java
--- a/src/org/python/modules/_jythonlib/_jythonlib.java
+++ b/src/org/python/modules/_jythonlib/_jythonlib.java
@@ -15,6 +15,8 @@
         dict.__setitem__("__doc__", __doc__);
         dict.__setitem__("__module__", new PyString("_jythonlib"));
         dict.__setitem__("dict_builder", dict_builder.TYPE);
+        dict.__setitem__("set_builder", set_builder.TYPE);
+
 
         // Hide from Python
         dict.__setitem__("classDictInit", null);
diff --git a/src/org/python/modules/_jythonlib/set_builder.java b/src/org/python/modules/_jythonlib/set_builder.java
new file mode 100644
--- /dev/null
+++ b/src/org/python/modules/_jythonlib/set_builder.java
@@ -0,0 +1,48 @@
+/* Copyright (c) Jython Developers */
+package org.python.modules._jythonlib;
+
+import org.python.core.Py;
+import org.python.core.PyObject;
+import org.python.core.PySet;
+import org.python.core.PySetDerived;
+import org.python.core.PyType;
+
+import java.util.Set;
+
+
+/* Support building PySet objects with arbitrary backing Set objects
+ * Uses a factory for efficiency.
+ *
+ * See the very similar dict_builder for more insight. But note that we do not
+ * impose the restriction that the set be concurrent, although this is generally
+ * what we would want.
+ */
+
+public class set_builder extends PyObject {
+
+    public static final PyType TYPE = PyType.fromClass(set_builder.class);
+    private final PyObject factory;
+    private final PyType set_type;
+
+    public set_builder(PyObject factory) {
+        super();
+        this.factory = factory;
+        this.set_type = null;
+    }
+
+    public set_builder(PyObject factory, PyType set_type) {
+        super();
+        this.factory = factory;
+        this.set_type = set_type;
+    }
+
+    public PyObject __call__(PyObject iterable) {
+        Set backing_set = (Set) (factory.__call__().__tojava__(Set.class));
+        if (set_type == null) {
+            return new PySet(backing_set, iterable == Py.None ? null : iterable);
+        } else {
+            return new PySetDerived(set_type, backing_set, iterable == Py.None ? null : iterable);
+        }
+    }
+
+}
diff --git a/src/templates/dict.derived b/src/templates/dict.derived
--- a/src/templates/dict.derived
+++ b/src/templates/dict.derived
@@ -2,3 +2,13 @@
 want_dict: true
 ctr:
 incl: object
+import: java.util.concurrent.ConcurrentMap
+rest:
+    public PyDictionaryDerived(PyType subtype, ConcurrentMap backingMap, boolean useBackingMap) {
+        super(subtype, backingMap, useBackingMap);
+        slots=new PyObject[subtype.getNumSlots()];
+        dict=subtype.instDict();
+        if (subtype.needsFinalizer()) {
+            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        }
+    }
diff --git a/src/templates/gderived.py b/src/templates/gderived.py
--- a/src/templates/gderived.py
+++ b/src/templates/gderived.py
@@ -25,6 +25,8 @@
 
 modif_re = re.compile(r"(?:\((\w+)\))?(\w+)")
 
+added_imports = []
+
 # os.path.samefile unavailable on Windows before Python v3.2
 if hasattr(os.path, "samefile"):
     # Good: available on this platform
@@ -43,6 +45,7 @@
                       'unary1',
                       'binary', 'ibinary',
                       'rest',
+                      'import',
                       'no_toString'
                       ]
 
@@ -82,6 +85,10 @@
             self.auxiliary = aux_gen.global_bindings
         return self.auxiliary[name]
 
+    def dire_import(self, name, parm, body):
+        global added_imports
+        added_imports = [x.strip() for x in parm.split(",")]
+
     def dire_require(self, name, parm, body):
         if body is not None:
             self.invalid('require', 'non-empty body')
@@ -217,6 +224,7 @@
     directives.execute(directives.load(fn), gen)
     result = gen.generate()
     result = hack_derived_header(outfile, result)
+    result = add_imports(outfile, result)
     print >> open(outfile, 'w'), result
     #gen.debug()
 
@@ -245,6 +253,23 @@
     
     return '\n'.join(result)
 
+def add_imports(fn, result):
+    if not added_imports:
+        return result
+    print 'Adding imports for: %s' % fn
+    result = result.splitlines()
+
+    def f():
+        added = False
+        for line in result:
+            if not added and line.startswith("import "):
+                added = True
+                for addition in added_imports:
+                    yield "import %s;" % (addition,)
+            yield line
+    
+    return '\n'.join(f())
+        
 
 if __name__ == '__main__':
     from gexpose import load_mappings, usage
diff --git a/src/templates/set.derived b/src/templates/set.derived
--- a/src/templates/set.derived
+++ b/src/templates/set.derived
@@ -2,3 +2,14 @@
 want_dict: true
 ctr:
 incl: object
+import: java.util.Set
+rest:
+    public PySetDerived(PyType subtype, Set backing_set, PyObject data) {
+        super(subtype, backing_set, data);
+        slots=new PyObject[subtype.getNumSlots()];
+        dict=subtype.instDict();
+        if (subtype.needsFinalizer()) {
+            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        }
+    }
+

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list