Fix and test issue 118. Clarify genmodel transformations.

This commit is contained in:
Gabriel 2011-07-05 00:44:57 +02:00
parent 5cfc74959f
commit 3fe1b4a3be
6 changed files with 159 additions and 99 deletions

View File

@ -35,7 +35,7 @@ class TestSchemaDiff(fixture.DB):
def _applyLatestModel(self): def _applyLatestModel(self):
diff = schemadiff.getDiffOfModelAgainstDatabase(self.meta, self.engine, excludeTables=['migrate_version']) diff = schemadiff.getDiffOfModelAgainstDatabase(self.meta, self.engine, excludeTables=['migrate_version'])
genmodel.ModelGenerator(diff,self.engine).applyModel() genmodel.ModelGenerator(diff,self.engine).runB2A()
@fixture.usedb() @fixture.usedb()
def test_functional(self): def test_functional(self):
@ -57,30 +57,44 @@ class TestSchemaDiff(fixture.DB):
# Check Python upgrade and downgrade of database from updated model. # Check Python upgrade and downgrade of database from updated model.
diff = schemadiff.getDiffOfModelAgainstDatabase(self.meta, self.engine, excludeTables=['migrate_version']) diff = schemadiff.getDiffOfModelAgainstDatabase(self.meta, self.engine, excludeTables=['migrate_version'])
decls, upgradeCommands, downgradeCommands = genmodel.ModelGenerator(diff,self.engine).toUpgradeDowngradePython() decls, upgradeCommands, downgradeCommands = genmodel.ModelGenerator(diff,self.engine).genB2AMigration()
self.assertEqualsIgnoreWhitespace(decls, '''
from migrate.changeset import schema # Feature test for a recent SQLa feature;
meta = MetaData() # expect different output in that case.
tmp_schemadiff = Table('tmp_schemadiff', meta, if repr(String()) == 'String()':
Column('id', Integer(), primary_key=True, nullable=False), self.assertEqualsIgnoreWhitespace(decls, '''
Column('name', UnicodeText(length=None)), from migrate.changeset import schema
Column('data', UnicodeText(length=None)), meta = MetaData()
) tmp_schemadiff = Table('tmp_schemadiff', meta,
''') Column('id', Integer, primary_key=True, nullable=False),
Column('name', UnicodeText),
Column('data', UnicodeText),
)
''')
else:
self.assertEqualsIgnoreWhitespace(decls, '''
from migrate.changeset import schema
meta = MetaData()
tmp_schemadiff = Table('tmp_schemadiff', meta,
Column('id', Integer(), primary_key=True, nullable=False),
Column('name', UnicodeText(length=None)),
Column('data', UnicodeText(length=None)),
)
''')
self.assertEqualsIgnoreWhitespace(upgradeCommands, self.assertEqualsIgnoreWhitespace(upgradeCommands,
'''meta.bind = migrate_engine '''meta.bind = migrate_engine
tmp_schemadiff.create()''') tmp_schemadiff.create()''')
self.assertEqualsIgnoreWhitespace(downgradeCommands, self.assertEqualsIgnoreWhitespace(downgradeCommands,
'''meta.bind = migrate_engine '''meta.bind = migrate_engine
tmp_schemadiff.drop()''') tmp_schemadiff.drop()''')
# Create table in database, now model should match database. # Create table in database, now model should match database.
self._applyLatestModel() self._applyLatestModel()
assertDiff(False, [], [], []) assertDiff(False, [], [], [])
# Check Python code gen from database. # Check Python code gen from database.
diff = schemadiff.getDiffOfModelAgainstDatabase(MetaData(), self.engine, excludeTables=['migrate_version']) diff = schemadiff.getDiffOfModelAgainstDatabase(MetaData(), self.engine, excludeTables=['migrate_version'])
src = genmodel.ModelGenerator(diff,self.engine).toPython() src = genmodel.ModelGenerator(diff,self.engine).genBDefinition()
exec src in locals() exec src in locals()
@ -105,25 +119,25 @@ class TestSchemaDiff(fixture.DB):
Column('data2',Integer(),nullable=True), Column('data2',Integer(),nullable=True),
) )
assertDiff(True, [], [], [self.table_name]) assertDiff(True, [], [], [self.table_name])
# Apply latest model changes and find no more diffs. # Apply latest model changes and find no more diffs.
self._applyLatestModel() self._applyLatestModel()
assertDiff(False, [], [], []) assertDiff(False, [], [], [])
if not self.engine.name == 'oracle': if not self.engine.name == 'oracle':
# Make sure data is still present. # Make sure data is still present.
result = self.engine.execute(self.table.select(self.table.c.id==dataId)) result = self.engine.execute(self.table.select(self.table.c.id==dataId))
rows = result.fetchall() rows = result.fetchall()
eq_(len(rows), 1) eq_(len(rows), 1)
eq_(rows[0].name, 'mydata') eq_(rows[0].name, 'mydata')
# Add data, later we'll make sure it's still present. # Add data, later we'll make sure it's still present.
result = self.engine.execute(self.table.insert(), id=2, name=u'mydata2', data2=123) result = self.engine.execute(self.table.insert(), id=2, name=u'mydata2', data2=123)
if SQLA_06: if SQLA_06:
dataId2 = result.inserted_primary_key[0] dataId2 = result.inserted_primary_key[0]
else: else:
dataId2 = result.last_inserted_ids()[0] dataId2 = result.last_inserted_ids()[0]
# Change column type in model. # Change column type in model.
self.meta.remove(self.table) self.meta.remove(self.table)
self.table = Table(self.table_name,self.meta, self.table = Table(self.table_name,self.meta,
@ -134,13 +148,13 @@ class TestSchemaDiff(fixture.DB):
# XXX test type diff # XXX test type diff
return return
assertDiff(True, [], [], [self.table_name]) assertDiff(True, [], [], [self.table_name])
# Apply latest model changes and find no more diffs. # Apply latest model changes and find no more diffs.
self._applyLatestModel() self._applyLatestModel()
assertDiff(False, [], [], []) assertDiff(False, [], [], [])
if not self.engine.name == 'oracle': if not self.engine.name == 'oracle':
# Make sure data is still present. # Make sure data is still present.
result = self.engine.execute(self.table.select(self.table.c.id==dataId2)) result = self.engine.execute(self.table.select(self.table.c.id==dataId2))
@ -148,11 +162,11 @@ class TestSchemaDiff(fixture.DB):
self.assertEquals(len(rows), 1) self.assertEquals(len(rows), 1)
self.assertEquals(rows[0].name, 'mydata2') self.assertEquals(rows[0].name, 'mydata2')
self.assertEquals(rows[0].data2, '123') self.assertEquals(rows[0].data2, '123')
# Delete data, since we're about to make a required column. # Delete data, since we're about to make a required column.
# Not even using sqlalchemy.PassiveDefault helps because we're doing explicit column select. # Not even using sqlalchemy.PassiveDefault helps because we're doing explicit column select.
self.engine.execute(self.table.delete(), id=dataId) self.engine.execute(self.table.delete(), id=dataId)
if not self.engine.name == 'firebird': if not self.engine.name == 'firebird':
# Change column nullable in model. # Change column nullable in model.
self.meta.remove(self.table) self.meta.remove(self.table)
@ -162,11 +176,11 @@ class TestSchemaDiff(fixture.DB):
Column('data2',String(255),nullable=False), Column('data2',String(255),nullable=False),
) )
assertDiff(True, [], [], [self.table_name]) # TODO test nullable diff assertDiff(True, [], [], [self.table_name]) # TODO test nullable diff
# Apply latest model changes and find no more diffs. # Apply latest model changes and find no more diffs.
self._applyLatestModel() self._applyLatestModel()
assertDiff(False, [], [], []) assertDiff(False, [], [], [])
# Remove table from model. # Remove table from model.
self.meta.remove(self.table) self.meta.remove(self.table)
assertDiff(True, [], [self.table_name], []) assertDiff(True, [], [self.table_name], [])

View File

@ -161,23 +161,44 @@ def upgrade(migrate_engine):
self.assertTrue('User.create()' in source_script) self.assertTrue('User.create()' in source_script)
self.assertTrue('User.drop()' in source_script) self.assertTrue('User.drop()' in source_script)
#@fixture.usedb() @fixture.usedb()
#def test_make_update_script_for_model_equals(self): def test_make_update_script_for_equal_models(self):
# """Try to make update script from two identical models""" """Try to make update script from two identical models"""
# self.setup_model_params() self.setup_model_params()
# self.write_file(self.first_model_path, self.base_source + self.model_source) self.write_file(self.first_model_path, self.base_source + self.model_source)
# self.write_file(self.second_model_path, self.base_source + self.model_source) self.write_file(self.second_model_path, self.base_source + self.model_source)
# source_script = self.pyscript.make_update_script_for_model( source_script = self.pyscript.make_update_script_for_model(
# engine=self.engine, engine=self.engine,
# oldmodel=load_model('testmodel_first:meta'), oldmodel=load_model('testmodel_first:meta'),
# model=load_model('testmodel_second:meta'), model=load_model('testmodel_second:meta'),
# repository=self.repo_path, repository=self.repo_path,
# ) )
# self.assertFalse('User.create()' in source_script) self.assertFalse('User.create()' in source_script)
# self.assertFalse('User.drop()' in source_script) self.assertFalse('User.drop()' in source_script)
@fixture.usedb()
def test_make_update_script_direction(self):
"""Check update scripts go in the right direction"""
self.setup_model_params()
self.write_file(self.first_model_path, self.base_source)
self.write_file(self.second_model_path, self.base_source + self.model_source)
source_script = self.pyscript.make_update_script_for_model(
engine=self.engine,
oldmodel=load_model('testmodel_first:meta'),
model=load_model('testmodel_second:meta'),
repository=self.repo_path,
)
self.assertTrue(0
< source_script.find('upgrade')
< source_script.find('User.create()')
< source_script.find('downgrade')
< source_script.find('User.drop()'))
def setup_model_params(self): def setup_model_params(self):
self.script_path = self.tmp_py() self.script_path = self.tmp_py()
@ -195,6 +216,8 @@ User = Table('User', meta,
self.repo = repository.Repository.create(self.repo_path, 'repo') self.repo = repository.Repository.create(self.repo_path, 'repo')
self.pyscript = PythonScript.create(self.script_path) self.pyscript = PythonScript.create(self.script_path)
sys.modules.pop('testmodel_first', None)
sys.modules.pop('testmodel_second', None)
def write_file(self, path, contents): def write_file(self, path, contents):
f = open(path, 'w') f = open(path, 'w')

View File

@ -1,9 +1,9 @@
""" """
Code to generate a Python model from a database or differences Code to generate a Python model from a database or differences
between a model and database. between a model and database.
Some of this is borrowed heavily from the AutoCode project at: Some of this is borrowed heavily from the AutoCode project at:
http://code.google.com/p/sqlautocode/ http://code.google.com/p/sqlautocode/
""" """
import sys import sys
@ -34,6 +34,13 @@ Base = declarative.declarative_base()
class ModelGenerator(object): class ModelGenerator(object):
"""Various transformations from an A, B diff.
In the implementation, A tends to be called the model and B
the database (although this is not true of all diffs).
The diff is directionless, but transformations apply the diff
in a particular direction, described in the method name.
"""
def __init__(self, diff, engine, declarative=False): def __init__(self, diff, engine, declarative=False):
self.diff = diff self.diff = diff
@ -89,7 +96,7 @@ class ModelGenerator(object):
else: else:
return """Column(%(name)r, %(commonStuff)s)""" % data return """Column(%(name)r, %(commonStuff)s)""" % data
def getTableDefn(self, table): def _getTableDefn(self, table):
out = [] out = []
tableName = table.name tableName = table.name
if self.declarative: if self.declarative:
@ -117,9 +124,15 @@ class ModelGenerator(object):
if bool_: if bool_:
for name in names: for name in names:
yield metadata.tables.get(name) yield metadata.tables.get(name)
def toPython(self): def genBDefinition(self):
"""Assume database is current and model is empty.""" """Generates the source code for a definition of B.
Assumes a diff where A is empty.
Was: toPython. Assume database (B) is current and model (A) is empty.
"""
out = [] out = []
if self.declarative: if self.declarative:
out.append(DECLARATIVE_HEADER) out.append(DECLARATIVE_HEADER)
@ -127,17 +140,22 @@ class ModelGenerator(object):
out.append(HEADER) out.append(HEADER)
out.append("") out.append("")
for table in self._get_tables(missingA=True): for table in self._get_tables(missingA=True):
out.extend(self.getTableDefn(table)) out.extend(self._getTableDefn(table))
return '\n'.join(out) return '\n'.join(out)
def toUpgradeDowngradePython(self, indent=' '): def genB2AMigration(self, indent=' '):
''' Assume model is most current and database is out-of-date. ''' '''Generate a migration from B to A.
Was: toUpgradeDowngradePython
Assume model (A) is most current and database (B) is out-of-date.
'''
decls = ['from migrate.changeset import schema', decls = ['from migrate.changeset import schema',
'meta = MetaData()'] 'meta = MetaData()']
for table in self._get_tables( for table in self._get_tables(
missingA=True,missingB=True,modified=True missingA=True,missingB=True,modified=True
): ):
decls.extend(self.getTableDefn(table)) decls.extend(self._getTableDefn(table))
upgradeCommands, downgradeCommands = [], [] upgradeCommands, downgradeCommands = [], []
for tableName in self.diff.tables_missing_from_A: for tableName in self.diff.tables_missing_from_A:
@ -175,16 +193,21 @@ class ModelGenerator(object):
'\n'.join([pre_command] + ['%s%s' % (indent, line) for line in downgradeCommands])) '\n'.join([pre_command] + ['%s%s' % (indent, line) for line in downgradeCommands]))
def _db_can_handle_this_change(self,td): def _db_can_handle_this_change(self,td):
"""Check if the database can handle going from B to A."""
if (td.columns_missing_from_B if (td.columns_missing_from_B
and not td.columns_missing_from_A and not td.columns_missing_from_A
and not td.columns_different): and not td.columns_different):
# Even sqlite can handle this. # Even sqlite can handle column additions.
return True return True
else: else:
return not self.engine.url.drivername.startswith('sqlite') return not self.engine.url.drivername.startswith('sqlite')
def applyModel(self): def runB2A(self):
"""Apply model to current database.""" """Goes from B to A.
Was: applyModel. Apply model (A) to current database (B).
"""
meta = sqlalchemy.MetaData(self.engine) meta = sqlalchemy.MetaData(self.engine)
@ -200,9 +223,9 @@ class ModelGenerator(object):
dbTable = self.diff.metadataB.tables[tableName] dbTable = self.diff.metadataB.tables[tableName]
td = self.diff.tables_different[tableName] td = self.diff.tables_different[tableName]
if self._db_can_handle_this_change(td): if self._db_can_handle_this_change(td):
for col in td.columns_missing_from_B: for col in td.columns_missing_from_B:
modelTable.columns[col].create() modelTable.columns[col].create()
for col in td.columns_missing_from_A: for col in td.columns_missing_from_A:

View File

@ -71,7 +71,7 @@ class ControlledSchema(object):
def changeset(self, version=None): def changeset(self, version=None):
"""API to Changeset creation. """API to Changeset creation.
Uses self.version for start version and engine.name Uses self.version for start version and engine.name
to get database name. to get database name.
""" """
@ -117,7 +117,7 @@ class ControlledSchema(object):
diff = schemadiff.getDiffOfModelAgainstDatabase( diff = schemadiff.getDiffOfModelAgainstDatabase(
model, self.engine, excludeTables=[self.repository.version_table] model, self.engine, excludeTables=[self.repository.version_table]
) )
genmodel.ModelGenerator(diff,self.engine).applyModel() genmodel.ModelGenerator(diff,self.engine).runB2A()
self.update_repository_table(self.version, int(self.repository.latest)) self.update_repository_table(self.version, int(self.repository.latest))
@ -217,4 +217,4 @@ class ControlledSchema(object):
diff = schemadiff.getDiffOfModelAgainstDatabase( diff = schemadiff.getDiffOfModelAgainstDatabase(
MetaData(), engine, excludeTables=[repository.version_table] MetaData(), engine, excludeTables=[repository.version_table]
) )
return genmodel.ModelGenerator(diff, engine, declarative).toPython() return genmodel.ModelGenerator(diff, engine, declarative).genBDefinition()

View File

@ -39,11 +39,11 @@ class ColDiff(object):
Container for differences in one :class:`~sqlalchemy.schema.Column` Container for differences in one :class:`~sqlalchemy.schema.Column`
between two :class:`~sqlalchemy.schema.Table` instances, ``A`` between two :class:`~sqlalchemy.schema.Table` instances, ``A``
and ``B``. and ``B``.
.. attribute:: col_A .. attribute:: col_A
The :class:`~sqlalchemy.schema.Column` object for A. The :class:`~sqlalchemy.schema.Column` object for A.
.. attribute:: col_B .. attribute:: col_B
The :class:`~sqlalchemy.schema.Column` object for B. The :class:`~sqlalchemy.schema.Column` object for B.
@ -51,15 +51,15 @@ class ColDiff(object):
.. attribute:: type_A .. attribute:: type_A
The most generic type of the :class:`~sqlalchemy.schema.Column` The most generic type of the :class:`~sqlalchemy.schema.Column`
object in A. object in A.
.. attribute:: type_B .. attribute:: type_B
The most generic type of the :class:`~sqlalchemy.schema.Column` The most generic type of the :class:`~sqlalchemy.schema.Column`
object in A. object in A.
""" """
diff = False diff = False
def __init__(self,col_A,col_B): def __init__(self,col_A,col_B):
@ -87,10 +87,10 @@ class ColDiff(object):
if not (A is None or B is None) and A!=B: if not (A is None or B is None) and A!=B:
self.diff=True self.diff=True
return return
def __nonzero__(self): def __nonzero__(self):
return self.diff return self.diff
class TableDiff(object): class TableDiff(object):
""" """
Container for differences in one :class:`~sqlalchemy.schema.Table` Container for differences in one :class:`~sqlalchemy.schema.Table`
@ -101,12 +101,12 @@ class TableDiff(object):
A sequence of column names that were found in B but weren't in A sequence of column names that were found in B but weren't in
A. A.
.. attribute:: columns_missing_from_B .. attribute:: columns_missing_from_B
A sequence of column names that were found in A but weren't in A sequence of column names that were found in A but weren't in
B. B.
.. attribute:: columns_different .. attribute:: columns_different
A dictionary containing information about columns that were A dictionary containing information about columns that were
@ -126,7 +126,7 @@ class TableDiff(object):
self.columns_missing_from_B or self.columns_missing_from_B or
self.columns_different self.columns_different
) )
class SchemaDiff(object): class SchemaDiff(object):
""" """
Compute the difference between two :class:`~sqlalchemy.schema.MetaData` Compute the difference between two :class:`~sqlalchemy.schema.MetaData`
@ -139,34 +139,34 @@ class SchemaDiff(object):
The length of a :class:`SchemaDiff` will give the number of The length of a :class:`SchemaDiff` will give the number of
changes found, enabling it to be used much like a boolean in changes found, enabling it to be used much like a boolean in
expressions. expressions.
:param metadataA: :param metadataA:
First :class:`~sqlalchemy.schema.MetaData` to compare. First :class:`~sqlalchemy.schema.MetaData` to compare.
:param metadataB: :param metadataB:
Second :class:`~sqlalchemy.schema.MetaData` to compare. Second :class:`~sqlalchemy.schema.MetaData` to compare.
:param labelA: :param labelA:
The label to use in messages about the first The label to use in messages about the first
:class:`~sqlalchemy.schema.MetaData`. :class:`~sqlalchemy.schema.MetaData`.
:param labelB: :param labelB:
The label to use in messages about the second The label to use in messages about the second
:class:`~sqlalchemy.schema.MetaData`. :class:`~sqlalchemy.schema.MetaData`.
:param excludeTables: :param excludeTables:
A sequence of table names to exclude. A sequence of table names to exclude.
.. attribute:: tables_missing_from_A .. attribute:: tables_missing_from_A
A sequence of table names that were found in B but weren't in A sequence of table names that were found in B but weren't in
A. A.
.. attribute:: tables_missing_from_B .. attribute:: tables_missing_from_B
A sequence of table names that were found in A but weren't in A sequence of table names that were found in A but weren't in
B. B.
.. attribute:: tables_different .. attribute:: tables_different
A dictionary containing information about tables that were found A dictionary containing information about tables that were found
@ -195,26 +195,26 @@ class SchemaDiff(object):
self.tables_missing_from_B = sorted( self.tables_missing_from_B = sorted(
A_table_names - B_table_names - excludeTables A_table_names - B_table_names - excludeTables
) )
self.tables_different = {} self.tables_different = {}
for table_name in A_table_names.intersection(B_table_names): for table_name in A_table_names.intersection(B_table_names):
td = TableDiff() td = TableDiff()
A_table = metadataA.tables[table_name] A_table = metadataA.tables[table_name]
B_table = metadataB.tables[table_name] B_table = metadataB.tables[table_name]
A_column_names = set(A_table.columns.keys()) A_column_names = set(A_table.columns.keys())
B_column_names = set(B_table.columns.keys()) B_column_names = set(B_table.columns.keys())
td.columns_missing_from_A = sorted( td.columns_missing_from_A = sorted(
B_column_names - A_column_names B_column_names - A_column_names
) )
td.columns_missing_from_B = sorted( td.columns_missing_from_B = sorted(
A_column_names - B_column_names A_column_names - B_column_names
) )
td.columns_different = {} td.columns_different = {}
for col_name in A_column_names.intersection(B_column_names): for col_name in A_column_names.intersection(B_column_names):
@ -226,7 +226,7 @@ class SchemaDiff(object):
if cd: if cd:
td.columns_different[col_name]=cd td.columns_different[col_name]=cd
# XXX - index and constraint differences should # XXX - index and constraint differences should
# be checked for here # be checked for here
@ -237,7 +237,7 @@ class SchemaDiff(object):
''' Summarize differences. ''' ''' Summarize differences. '''
out = [] out = []
column_template =' %%%is: %%r' % self.label_width column_template =' %%%is: %%r' % self.label_width
for names,label in ( for names,label in (
(self.tables_missing_from_A,self.labelA), (self.tables_missing_from_A,self.labelA),
(self.tables_missing_from_B,self.labelB), (self.tables_missing_from_B,self.labelB),
@ -248,7 +248,7 @@ class SchemaDiff(object):
label,', '.join(sorted(names)) label,', '.join(sorted(names))
) )
) )
for name,td in sorted(self.tables_different.items()): for name,td in sorted(self.tables_different.items()):
out.append( out.append(
' table with differences: %s' % name ' table with differences: %s' % name
@ -267,7 +267,7 @@ class SchemaDiff(object):
out.append(' column with differences: %s' % name) out.append(' column with differences: %s' % name)
out.append(column_template % (self.labelA,cd.col_A)) out.append(column_template % (self.labelA,cd.col_A))
out.append(column_template % (self.labelB,cd.col_B)) out.append(column_template % (self.labelB,cd.col_B))
if out: if out:
out.insert(0, 'Schema diffs:') out.insert(0, 'Schema diffs:')
return '\n'.join(out) return '\n'.join(out)

View File

@ -25,7 +25,7 @@ class PythonScript(base.BaseScript):
@classmethod @classmethod
def create(cls, path, **opts): def create(cls, path, **opts):
"""Create an empty migration script at specified path """Create an empty migration script at specified path
:returns: :class:`PythonScript instance <migrate.versioning.script.py.PythonScript>`""" :returns: :class:`PythonScript instance <migrate.versioning.script.py.PythonScript>`"""
cls.require_notfound(path) cls.require_notfound(path)
@ -38,7 +38,7 @@ class PythonScript(base.BaseScript):
def make_update_script_for_model(cls, engine, oldmodel, def make_update_script_for_model(cls, engine, oldmodel,
model, repository, **opts): model, repository, **opts):
"""Create a migration script based on difference between two SA models. """Create a migration script based on difference between two SA models.
:param repository: path to migrate repository :param repository: path to migrate repository
:param oldmodel: dotted.module.name:SAClass or SAClass object :param oldmodel: dotted.module.name:SAClass or SAClass object
:param model: dotted.module.name:SAClass or SAClass object :param model: dotted.module.name:SAClass or SAClass object
@ -50,7 +50,7 @@ class PythonScript(base.BaseScript):
:returns: Upgrade / Downgrade script :returns: Upgrade / Downgrade script
:rtype: string :rtype: string
""" """
if isinstance(repository, basestring): if isinstance(repository, basestring):
# oh dear, an import cycle! # oh dear, an import cycle!
from migrate.versioning.repository import Repository from migrate.versioning.repository import Repository
@ -61,12 +61,12 @@ class PythonScript(base.BaseScript):
# Compute differences. # Compute differences.
diff = schemadiff.getDiffOfModelAgainstModel( diff = schemadiff.getDiffOfModelAgainstModel(
oldmodel,
model, model,
oldmodel,
excludeTables=[repository.version_table]) excludeTables=[repository.version_table])
# TODO: diff can be False (there is no difference?) # TODO: diff can be False (there is no difference?)
decls, upgradeCommands, downgradeCommands = \ decls, upgradeCommands, downgradeCommands = \
genmodel.ModelGenerator(diff,engine).toUpgradeDowngradePython() genmodel.ModelGenerator(diff,engine).genB2AMigration()
# Store differences into file. # Store differences into file.
src = Template(opts.pop('templates_path', None)).get_script(opts.pop('templates_theme', None)) src = Template(opts.pop('templates_path', None)).get_script(opts.pop('templates_theme', None))
@ -86,7 +86,7 @@ class PythonScript(base.BaseScript):
@classmethod @classmethod
def verify_module(cls, path): def verify_module(cls, path):
"""Ensure path is a valid script """Ensure path is a valid script
:param path: Script location :param path: Script location
:type path: string :type path: string
:raises: :exc:`InvalidScriptError <migrate.exceptions.InvalidScriptError>` :raises: :exc:`InvalidScriptError <migrate.exceptions.InvalidScriptError>`
@ -101,7 +101,7 @@ class PythonScript(base.BaseScript):
return module return module
def preview_sql(self, url, step, **args): def preview_sql(self, url, step, **args):
"""Mocks SQLAlchemy Engine to store all executed calls in a string """Mocks SQLAlchemy Engine to store all executed calls in a string
and runs :meth:`PythonScript.run <migrate.versioning.script.py.PythonScript.run>` and runs :meth:`PythonScript.run <migrate.versioning.script.py.PythonScript.run>`
:returns: SQL file :returns: SQL file
@ -119,7 +119,7 @@ class PythonScript(base.BaseScript):
return go(url, step, **args) return go(url, step, **args)
def run(self, engine, step): def run(self, engine, step):
"""Core method of Script file. """Core method of Script file.
Exectues :func:`update` or :func:`downgrade` functions Exectues :func:`update` or :func:`downgrade` functions
:param engine: SQLAlchemy Engine :param engine: SQLAlchemy Engine