and then applied changes until everything except the doctests passed.
I haven't done extensive testing, and in fact, have only done testing
on mysql 5.1.14, but I figured in the off chance someone else cared,
here are my ugly patches (as shown by svn diff)
david
Index: test/changeset/test_changeset.py
===================================================================
--- test/changeset/test_changeset.py (revision 345)
+++ test/changeset/test_changeset.py (working copy)
@@ -324,33 +324,33 @@
# ...as a function, given a column object and the new name
alter_column(self.table.c.data, name='atad')
- self.refresh_table(self.table)
- self.assert_('data' not in self.table.c)
- self.assert_('atad' in self.table.c)
+ self.refresh_table(self.table.name)
+ self.assert_('data' not in self.table.c.keys())
+ self.assert_('atad' in self.table.c.keys())
#self.assertRaises(AttributeError,getattr,self.table.c,'data')
self.table.c.atad # Should not raise exception
self.assertEquals(num_rows(self.table.c.atad,content),1)
# ...as a method, given a new name
self.table.c.atad.alter(name='data')
- self.refresh_table(self.table)
- self.assert_('atad' not in self.table.c)
+ self.refresh_table(self.table.name)
+ self.assert_('atad' not in self.table.c.keys())
self.table.c.data # Should not raise exception
self.assertEquals(num_rows(self.table.c.data,content),1)
# ...as a function, given a new object
col =
Column('atad',String(40),default=self.table.c.data.default)
alter_column(self.table.c.data, col)
- self.refresh_table(self.table)
- self.assert_('data' not in self.table.c)
+ self.refresh_table(self.table.name)
+ self.assert_('data' not in self.table.c.keys())
self.table.c.atad # Should not raise exception
self.assertEquals(num_rows(self.table.c.atad,content),1)
# ...as a method, given a new object
col =
Column('data',String(40),default=self.table.c.atad.default)
self.table.c.atad.alter(col)
- self.refresh_table(self.table)
- self.assert_('atad' not in self.table.c)
+ self.refresh_table(self.table.name)
+ self.assert_('atad' not in self.table.c.keys())
self.table.c.data # Should not raise exception
self.assertEquals(num_rows(self.table.c.data,content),1)
@@ -363,12 +363,12 @@
# add
self.table.c.data.alter(foreign_key=ForeignKey(self.table.c.id))
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assert_(self.table.c.data.foreign_key is not None)
# drop
self.table.c.data.alter(foreign_key=None)
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assert_(self.table.c.data.foreign_key is None)
@fixture.usedb(not_supported='sqlite')
@@ -376,13 +376,13 @@
"""Can change a column's type"""
# Entire column definition given
self.table.c.data.alter(Column('data',String(42)))
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assert_(isinstance(self.table.c.data.type,String))
self.assertEquals(self.table.c.data.type.length,42)
# Just the new type
self.table.c.data.alter(type=String(21))
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assert_(isinstance(self.table.c.data.type,String))
self.assertEquals(self.table.c.data.type.length,21)
@@ -391,7 +391,7 @@
self.assertEquals(self.table.c.id.nullable,False)
self.table.c.id.alter(type=String(20))
self.assertEquals(self.table.c.id.nullable,False)
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assert_(isinstance(self.table.c.id.type,String))
@fixture.usedb(not_supported='sqlite')
@@ -406,7 +406,7 @@
# Just the new default
default = 'my_default'
self.table.c.data.alter(default=PassiveDefault(default))
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
#self.assertEquals(self.table.c.data.default.arg,default)
# TextClause returned by autoload
self.assert_(default in str(self.table.c.data.default.arg))
@@ -414,12 +414,12 @@
# Column object
default = 'your_default'
self.table.c.data.alter(Column('data',String(40),default=PassiveDefault(default)))
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assert_(default in str(self.table.c.data.default.arg))
# Remove default
self.table.c.data.alter(default=None)
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
# default isn't necessarily None for Oracle
#self.assert_(self.table.c.data.default is
None,self.table.c.data.default)
self.engine.execute(self.table.insert(),id=11)
@@ -435,12 +435,12 @@
# Column object
self.table.c.data.alter(Column('data',String(40),nullable=False))
self.table.nullable=None
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assertEquals(self.table.c.data.nullable,False)
# Just the new status
self.table.c.data.alter(nullable=True)
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assertEquals(self.table.c.data.nullable,True)
@fixture.usedb(not_supported='sqlite')
@@ -452,12 +452,12 @@
# Entire column definition
self.table.c.data.alter(Column('data',String,primary_key=True))
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assertEquals(len(self.table.primary_key),2)
# Just the new status
self.table.c.data.alter(primary_key=False)
- self.refresh_table(self.table)
+ self.refresh_table(self.table.name)
self.assertEquals(len(self.table.primary_key),1)
class TestColumnDelta(fixture.Base):
Index: test/changeset/test_constraint.py
===================================================================
--- test/changeset/test_constraint.py (revision 345)
+++ test/changeset/test_constraint.py (working copy)
@@ -28,7 +28,7 @@
schema.PrimaryKeyConstraint),self.table.primary_key.__class__)
def _define_pk(self,*cols):
# Add a pk by creating a PK constraint
- pk = PrimaryKeyConstraint(*cols)
+ pk = PrimaryKeyConstraint(table=self.table, *cols)
self.assertEquals(list(pk.columns),list(cols))
if self.url.startswith('oracle'):
# Can't drop Oracle PKs without an explicit name
@@ -54,11 +54,11 @@
def test_define_fk(self):
"""FK constraints can be defined, created, and dropped"""
# FK target must be unique
- pk = PrimaryKeyConstraint(self.table.c.id)
+ pk = PrimaryKeyConstraint(self.table.c.id, table=self.table)
pk.create()
# Add a FK by creating a FK constraint
self.assert_(self.table.c.fkey.foreign_key is None)
- fk = ForeignKeyConstraint([self.table.c.fkey],
[self.table.c.id])
+ fk = ForeignKeyConstraint([self.table.c.fkey],
[self.table.c.id], table=self.table)
self.assert_(self.table.c.fkey.foreign_key is not None)
#self.assertEquals(fk.c, fk.columns)
self.assertEquals(list(fk.columns), [self.table.c.fkey])
@@ -77,7 +77,7 @@
fk.create()
self.engine.echo=False
print 'dropped'
- self.table = self.refresh_table()
+ self.refresh_table()
self.assert_(self.table.c.fkey.foreign_key is not None)
print 'drop...'
@@ -85,7 +85,7 @@
fk.drop()
self.engine.echo=False
print 'dropped'
- self.table = self.refresh_table()
+ self.refresh_table()
self.assert_(self.table.c.fkey.foreign_key is None)
@fixture.usedb()
@@ -96,6 +96,7 @@
@fixture.usedb()
def test_define_pk_multi(self):
"""Multicolumn PK constraints can be defined, created, and
dropped"""
+ self.engine.echo=True
self._define_pk(self.table.c.id,self.table.c.fkey)
@@ -104,7 +105,7 @@
def setUp(self):
fixture.DB.setUp(self)
- self.meta = BoundMetaData(self.engine)
+ self.meta = MetaData(self.engine)
self.table = Table('mytable',self.meta,
Column('id',Integer),
Column('fkey',String(40)),
Index: migrate/changeset/ansisql.py
===================================================================
--- migrate/changeset/ansisql.py (revision 345)
+++ migrate/changeset/ansisql.py (working copy)
@@ -3,8 +3,10 @@
happen to work with multiple databases.
"""
import sqlalchemy as sa
+from sqlalchemy.engine.base import Connection, Dialect
from migrate.changeset import constraint,exceptions
+
SchemaIterator = sa.engine.SchemaIterator
ANSISchemaGenerator = sa.ansisql.ANSISchemaGenerator
@@ -57,6 +59,16 @@
class ANSIColumnGenerator(AlterTableVisitor,ANSISchemaGenerator):
"""Extends ansisql generator for column creation (alter table add
col)"""
+ def __init__(self, *args, **kwargs):
+ dialect = None
+ if isinstance(args[0], Connection):
+ dialect = args[0].engine.dialect
+ elif isinstance(args[0], Dialect):
+ dialect = args[0]
+ else:
+ raise exceptions.Error("Cannot infer dialect in
__init__")
+ super(ANSIColumnGenerator, self).__init__(dialect, *args,
**kwargs)
+
def visit_column(self,column):
"""Create a column (table already exists); #32"""
table = self.start_alter_table(column)
@@ -197,7 +209,7 @@
self.execute()
-class ANSIConstraintCommon(RawAlterTableVisitor):
+class ANSIConstraintCommon(AlterTableVisitor):
"""
Migrate's constraints require a separate creation function from
SA's:
Migrate's constraints are created independently of a table; SA's
are
@@ -212,13 +224,13 @@
class ANSIConstraintGenerator(ANSIConstraintCommon):
def get_constraint_specification(self,cons,**kwargs):
- if isinstance(cons,PrimaryKeyConstraint):
+ if isinstance(cons,constraint.PrimaryKeyConstraint):
col_names = ','.join([i.name for i in cons.columns])
ret = "PRIMARY KEY (%s)"%col_names
if cons.name:
# Named constraint
ret = ("CONSTRAINT %s "%cons.name)+ret
- elif isinstance(cons,ForeignKeyConstraint):
+ elif isinstance(cons,constraint.ForeignKeyConstraint):
params = dict(
columns=','.join([c.name for c in cons.columns]),
reftable=cons.reftable,
Index: migrate/changeset/__init__.py
===================================================================
--- migrate/changeset/__init__.py (revision 345)
+++ migrate/changeset/__init__.py (working copy)
@@ -1,3 +1,2 @@
from migrate.changeset.schema import *
from migrate.changeset.constraint import *
-
Index: migrate/changeset/databases/mysql.py
===================================================================
--- migrate/changeset/databases/mysql.py (revision 345)
+++ migrate/changeset/databases/mysql.py (working copy)
@@ -57,3 +57,5 @@
columngenerator = MySQLColumnGenerator
columndropper = MySQLColumnDropper
schemachanger = MySQLSchemaChanger
+ constraintgenerator = MySQLConstraintGenerator
+ constraintdropper = MySQLConstraintDropper
Index: migrate/changeset/schema.py
===================================================================
--- migrate/changeset/schema.py (revision 345)
+++ migrate/changeset/schema.py (working copy)
@@ -55,7 +55,7 @@
def _engine_run_visitor(engine,visitorcallable,element,**kwargs):
conn = engine.connect()
try:
-
element.accept_schema_visitor(visitorcallable(engine,conn.proxy,connection=conn))
+ element.accept_schema_visitor(visitorcallable(engine.dialect,
connection=conn))
finally:
conn.close()
@@ -115,8 +115,8 @@
def accept_schema_visitor(self,visitor):
if isinstance(self.item,sqlalchemy.Table):
suffix = 'table'
- #elif isinstance(self.item,sqlalchemy.Column):
- # suffix = 'column'
+ elif isinstance(self.item,sqlalchemy.Column):
+ suffix = 'column'
elif isinstance(self.item,sqlalchemy.Index):
suffix = 'index'
funcname = 'visit_%s'%suffix
Index: migrate/changeset/constraint.py
===================================================================
--- migrate/changeset/constraint.py (revision 345)
+++ migrate/changeset/constraint.py (working copy)
@@ -39,7 +39,15 @@
return func(self)
def autoname(self):
raise NotImplementedError()
-
+
+
+def _engine_run_visitor(engine,visitorcallable,element,**kwargs):
+ conn = engine.connect()
+ try:
+ element.accept_schema_visitor(visitorcallable(conn))
+ finally:
+ conn.close()
+
class
PrimaryKeyConstraint(ConstraintChangeset,schema.PrimaryKeyConstraint):
def __init__(self,*cols,**kwargs):
colnames,table = self._normalize_columns(cols)
@@ -51,16 +59,25 @@
def _set_parent(self,table):
self.table = table
return super(ConstraintChangeset,self)._set_parent(table)
+
+ def create(self, *args, **kwargs):
+ from migrate.changeset.databases.visitor import
get_engine_visitor
+ visitorcallable =
get_engine_visitor(self.table.engine,'constraintgenerator')
+ _engine_run_visitor (self.table.engine, visitorcallable,
self)
+
def autoname(self):
"""Mimic the database's automatic constraint names"""
ret = "%(table)s_pkey"%dict(
table=self.table.name,
)
return ret
+
def drop(self,*args,**kwargs):
- ret = super(PrimaryKeyConstraint,self).drop(*args,**kwargs)
+ from migrate.changeset.databases.visitor import
get_engine_visitor
+ visitorcallable =
get_engine_visitor(self.table.engine,'constraintdropper')
+ _engine_run_visitor (self.table.engine, visitorcallable,
self)
self.columns.clear()
- return ret
+ return self
def accept_schema_visitor(self,visitor,*p,**k):
#return visitor.visit_constraint(self,*p,**k)
@@ -91,7 +108,20 @@
reftable=self.reftable.name,
)
return ret
+
+ def create(self, *args, **kwargs):
+ from migrate.changeset.databases.visitor import
get_engine_visitor
+ visitorcallable =
get_engine_visitor(self.table.engine,'constraintgenerator')
+ _engine_run_visitor (self.table.engine, visitorcallable,
self)
+ return self
+ def drop(self,*args,**kwargs):
+ from migrate.changeset.databases.visitor import
get_engine_visitor
+ visitorcallable =
get_engine_visitor(self.table.engine,'constraintdropper')
+ _engine_run_visitor (self.table.engine, visitorcallable,
self)
+ self.columns.clear()
+ return self
+
def accept_schema_visitor(self,visitor,*p,**k):
func = 'visit_migrate_foreign_key_constraint'
return self._accept_schema_visitor(visitor,func,*p,**k)
2007/10/31, dykang <dyk...@gmail.com>:
On Nov 1, 2:18 pm, "Jan Dittberner" <jan.dittber...@googlemail.com>
wrote:
I think we could also use some basic help with getting the
documentation moved into the google code wiki.
I TurboGeras 2/pylons users would benifit from a standard schema
migration system, and it's definitely a feature I think TG2 needs to
compete successfully with rails and django. We'll definitely be
defaulting to SA 0.4. So Migrate 0.4 compatibility is a big goal.
--Mark
--
Mark Ramm-Christensen
email: mark at compoundthinking dot com
blog: www.compoundthinking.com/blog
http://code.google.com/p/sqlalchemy-migrate/wiki/Todo
and a ticket for tracking the progress on moving the documentation to
the wiki
http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=1
Regards
Jan
--
Jan Dittberner
web: http://www.dittberner.info/