]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- MetaData and all SchemaItems are safe to use with pickle. slow
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 30 Jun 2007 00:20:26 +0000 (00:20 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 30 Jun 2007 00:20:26 +0000 (00:20 +0000)
table reflections can be dumped into a pickled file to be reused later.
Just reconnect the engine to the metadata after unpickling. [ticket:619]

CHANGES
lib/sqlalchemy/schema.py
test/engine/reflection.py

diff --git a/CHANGES b/CHANGES
index 9bfca28cd8daf1bfc25c97843c9a19f29507f998..220a6fe3174ecfd2de2ead34a9012793fc15aa84 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -29,6 +29,9 @@
       trip over synonyms (and others) that are named after the column's actual
       "key" (since, column_prefix means "dont use the key").
 - sql
+    - MetaData and all SchemaItems are safe to use with pickle.  slow
+      table reflections can be dumped into a pickled file to be reused later.
+      Just reconnect the engine to the metadata after unpickling. [ticket:619]
     - fixed grouping of compound selects to give correct results. will break
       on sqlite in some cases, but those cases were producing incorrect
       results anyway, sqlite doesn't support grouped compound selects
index a27adf06eec604bec3cc977182c3669a095186c4..5d3ca694b00551e2fb83a2aeaef5c28a1b248494 100644 (file)
@@ -1094,6 +1094,15 @@ class MetaData(SchemaItem):
         if engine or url:
             self.connect(engine or url, **kwargs)
 
+    def __getstate__(self):
+        return {'tables':self.tables, 'name':self.name, 'casesensitive':self._case_sensitive_setting}
+    
+    def __setstate__(self, state):
+        self.tables = state['tables']
+        self.name = state['name']
+        self._case_sensitive_setting = state['casesensitive']
+        self._engine = None
+        
     def is_bound(self):
         """return True if this MetaData is bound to an Engine."""
         return self._engine is not None
index ee373f43e8e5357c4d49e4af806c83ad31f89627..a9a1f934e5c4575101bc74e239ad132b2920e81c 100644 (file)
@@ -1,6 +1,6 @@
 from testbase import PersistTest
 import testbase
-
+import pickle
 import sqlalchemy.ansisql as ansisql
 
 from sqlalchemy import *
@@ -105,7 +105,7 @@ class ReflectionTest(PersistTest):
         finally:
             addresses.drop()
             users.drop()
-            
+    
     def testoverridecolumns(self):
         """test that you can override columns which contain foreign keys to other reflected tables"""
         meta = BoundMetaData(testbase.db)
@@ -329,49 +329,78 @@ class ReflectionTest(PersistTest):
             meta.drop_all()
 
             
-    def testtometadata(self):
-        meta = MetaData('md1')
-        meta2 = MetaData('md2')
+    def test_to_metadata(self):
+        meta = MetaData()
         
         table = Table('mytable', meta,
             Column('myid', Integer, primary_key=True),
-            Column('name', String, nullable=False),
+            Column('name', String(40), nullable=False),
             Column('description', String(30), CheckConstraint("description='hi'")),
-            UniqueConstraint('name')
+            UniqueConstraint('name'),
+            mysql_engine='InnoDB'
         )
         
         table2 = Table('othertable', meta,
             Column('id', Integer, primary_key=True),
-            Column('myid', Integer, ForeignKey('mytable.myid'))
+            Column('myid', Integer, ForeignKey('mytable.myid')),
+            mysql_engine='InnoDB'
             )
-            
-        
-        table_c = table.tometadata(meta2)
-        table2_c = table2.tometadata(meta2)
-
-        assert table is not table_c
-        assert table_c.c.myid.primary_key
-        assert not table_c.c.name.nullable 
-        assert table_c.c.description.nullable 
-        assert table.primary_key is not table_c.primary_key
-        assert [x.name for x in table.primary_key] == [x.name for x in table_c.primary_key]
-        assert list(table2_c.c.myid.foreign_keys)[0].column is table_c.c.myid
-        assert list(table2_c.c.myid.foreign_keys)[0].column is not table.c.myid
-        for c in table_c.c.description.constraints:
-            if isinstance(c, CheckConstraint):
-                break
-        else:
-            assert False
-        assert c.sqltext=="description='hi'"
         
-        for c in table_c.constraints:
-            if isinstance(c, UniqueConstraint):
-                break
-        else:
-            assert False
-        assert c.columns.contains_column(table_c.c.name)
-        assert not c.columns.contains_column(table.c.name)
+        def test_to_metadata():
+            meta2 = MetaData()
+            table_c = table.tometadata(meta2)
+            table2_c = table2.tometadata(meta2)
+            return (table_c, table2_c)
+            
+        def test_pickle():
+            meta.connect(testbase.db)
+            meta2 = pickle.loads(pickle.dumps(meta))
+            assert meta2.engine is None
+            return (meta2.tables['mytable'], meta2.tables['othertable'])
+
+        def test_pickle_via_reflect():
+            # this is the most common use case, pickling the results of a
+            # database reflection
+            meta2 = MetaData(engine=testbase.db)
+            t1 = Table('mytable', meta2, autoload=True)
+            t2 = Table('othertable', meta2, autoload=True)
+            meta3 = pickle.loads(pickle.dumps(meta2))
+            assert meta3.engine is None
+            assert meta3.tables['mytable'] is not t1
+            return (meta3.tables['mytable'], meta3.tables['othertable'])
+            
+        meta.create_all(testbase.db)    
+        try:
+            for test, has_constraints in ((test_to_metadata, True), (test_pickle, True), (test_pickle_via_reflect, False)):
+                table_c, table2_c = test()
+                assert table is not table_c
+                assert table_c.c.myid.primary_key
+                assert not table_c.c.name.nullable 
+                assert table_c.c.description.nullable 
+                assert table.primary_key is not table_c.primary_key
+                assert [x.name for x in table.primary_key] == [x.name for x in table_c.primary_key]
+                assert list(table2_c.c.myid.foreign_keys)[0].column is table_c.c.myid
+                assert list(table2_c.c.myid.foreign_keys)[0].column is not table.c.myid
+                
+                # constraints dont get reflected for any dialect right now
+                if has_constraints:
+                    for c in table_c.c.description.constraints:
+                        if isinstance(c, CheckConstraint):
+                            break
+                    else:
+                        assert False
+                    assert c.sqltext=="description='hi'"
         
+                    for c in table_c.constraints:
+                        if isinstance(c, UniqueConstraint):
+                            break
+                    else:
+                        assert False
+                    assert c.columns.contains_column(table_c.c.name)
+                    assert not c.columns.contains_column(table.c.name)
+        finally:
+            meta.drop_all(testbase.db)
+            
     # mysql throws its own exception for no such table, resulting in 
     # a sqlalchemy.SQLError instead of sqlalchemy.NoSuchTableError.
     # this could probably be fixed at some point.