]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
fixed up expunge() and the continuing circular refs in attributes, added a unit test...
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 19 Apr 2006 19:33:51 +0000 (19:33 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 19 Apr 2006 19:33:51 +0000 (19:33 +0000)
lib/sqlalchemy/attributes.py
lib/sqlalchemy/mapping/objectstore.py
lib/sqlalchemy/sql.py
test/attributes.py
test/masscreate.py
test/massload.py [new file with mode: 0644]

index e399e7ed0ca981ea65e7e2a91032910936952eff..98884df4413ab83e523e6bc7b741b05061878196 100644 (file)
@@ -78,10 +78,10 @@ class ManagedAttribute(object):
     which occurs through the SmartProperty property object ultimately calls upon 
     ManagedAttribute objects associated with the instance via this dictionary."""
     def __init__(self, obj, key):
-        #self.__obj = weakref.ref(obj)
-        self.obj = obj
+        self.__obj = weakref.ref(obj)
+        #self.obj = obj
         self.key = key
-    #obj = property(lambda s:s.__obj())
+    obj = property(lambda s:s.__obj())
     def history(self, **kwargs):
         return self
     def plain_init(self, *args, **kwargs):
index faf5ddbd6b1796fcf78784aee2c7a1241009a093..91f94708511e0d6e0b6e4c1e4d94fedf99c7949a 100644 (file)
@@ -94,7 +94,7 @@ class Session(object):
 
     def expunge(self, *obj):
         for o in obj:
-            self.uow.expunge(obj)
+            self.uow.expunge(o)
             
     def register_clean(self, obj):
         self._bind_to(obj)
index 02e1619a1579b22ce78d5f9b40361433a44244b2..1af02faaccdae405fbdc78eca7bf885ab1f89169 100644 (file)
@@ -131,7 +131,8 @@ def not_(clause):
 def between_(ctest, cleft, cright):
     """ returns BETWEEN predicate clause (clausetest BETWEEN clauseleft AND clauseright) """
     return BooleanExpression(ctest, and_(cleft, cright), 'BETWEEN')
-        
+between = between_
+   
 def cast(clause, totype, **kwargs):
     """ returns CAST function CAST(clause AS totype) 
         Use with a sqlalchemy.types.TypeEngine object, i.e
@@ -517,6 +518,8 @@ class CompareMixin(object):
         return Label(name, self, self.type)
     def distinct(self):
         return CompoundClause(None,"DISTINCT", self)
+    def between(self, cleft, cright):
+        return between_(self, cleft, cright)
     def op(self, operator):
         return lambda other: self._compare(operator, other)
     # and here come the math operators:
index 4c4c7585c5381f263f85d76ce5aab2a646d095e4..bff864fa6929d7324602d406af15ec0aecbcdfd2 100644 (file)
@@ -43,9 +43,9 @@ class AttributesTest(PersistTest):
         manager.register_attribute(MyTest, 'user_id', uselist = False)
         manager.register_attribute(MyTest, 'user_name', uselist = False)
         manager.register_attribute(MyTest, 'email_address', uselist = False)
-       x = MyTest()
-       x.user_id=7
-       pickle.dumps(x)
+        x = MyTest()
+        x.user_id=7
+        pickle.dumps(x)
 
     def testlist(self):
         class User(object):pass
index 4321c210fa7dae3ec3bdda7fb2876504c4488e58..885c1f6537f151fd168cda4a3a6e607bfffaf4f4 100644 (file)
@@ -2,6 +2,7 @@
 
 from sqlalchemy.attributes import *
 import time
+import gc
 
 manage_attributes = True
 init_attributes = manage_attributes and True
@@ -32,7 +33,9 @@ for i in range(0,130):
         if init_attributes:
             attr_manager.init_attr(a)
         a.email = 'foo@bar.com'
-        u.addresses.append(u)
-
+        u.addresses.append(a)
+#    gc.collect()
+    print len(managed_attributes)
+#    managed_attributes.clear()
 total = time.time() - now
 print "Total time", total
diff --git a/test/massload.py b/test/massload.py
new file mode 100644 (file)
index 0000000..d367469
--- /dev/null
@@ -0,0 +1,65 @@
+from testbase import PersistTest, AssertMixin
+import unittest, sys, os
+from sqlalchemy import *
+import sqlalchemy.attributes as attributes
+import StringIO
+import testbase
+import gc
+
+db = testbase.db
+
+NUM = 25000
+
+"""
+we are testing session.expunge() here, also that the attributes and unitofwork packages dont keep dereferenced
+stuff hanging around.
+
+for best results, dont run with sqlite :memory: database, and keep an eye on top while it runs"""
+
+class LoadTest(AssertMixin):
+    def setUpAll(self):
+        db.echo = False
+        global items
+        items = Table('items', db, 
+            Column('item_id', Integer, primary_key=True),
+            Column('value', String(100)))
+        items.create()
+        db.echo = testbase.echo
+    def tearDownAll(self):
+        db.echo = False
+        items.drop()
+        items.deregister()
+        db.echo = testbase.echo
+    def setUp(self):
+        objectstore.clear()
+        clear_mappers()
+        for x in range(1,NUM/500+1):
+            l = []
+            for y in range(x*500-500, x*500):
+                l.append({'item_id':y, 'value':'this is item #%d' % y})
+            items.insert().execute(*l)
+            
+    def testload(self):
+        class Item(object):pass
+            
+        m = mapper(Item, items)
+        
+        for x in range (1,NUM/100):
+            # this is not needed with cpython which clears non-circular refs immediately
+            #gc.collect()
+            l = m.select(items.c.item_id.between(x*100 - 100, x*100 - 1))
+            assert len(l) == 100
+            print "loaded ", len(l), " items "
+            # modifying each object will insure that the objects get placed in the "dirty" list
+            # and will hang around until expunged
+            for a in l:
+                a.value = 'changed...'
+            assert len(objectstore.get_session().dirty) == len(l)
+            assert len(objectstore.get_session().identity_map) == len(l)
+            assert len(attributes.managed_attributes) == len(l)
+            print len(objectstore.get_session().dirty)
+            print len(objectstore.get_session().identity_map)
+            #objectstore.expunge(*l)
+
+if __name__ == "__main__":
+    testbase.main()