PKDN58„Äv v EGG-INFO/SOURCES.txtCHANGELOG README setup.cfg setup.py test_db.cfg.tmpl docs/changeset.rst docs/download.rst docs/index.rst docs/versioning.rst docs/theme/almodovar.css docs/theme/layout.css docs/theme/layout.html migrate/__init__.py migrate/run.py migrate.egg-info/PKG-INFO migrate.egg-info/SOURCES.txt migrate.egg-info/dependency_links.txt migrate.egg-info/requires.txt migrate.egg-info/top_level.txt migrate/changeset/__init__.py migrate/changeset/ansisql.py migrate/changeset/constraint.py migrate/changeset/exceptions.py migrate/changeset/util.py migrate/changeset/databases/__init__.py migrate/changeset/databases/mysql.py migrate/changeset/databases/oracle.py migrate/changeset/databases/postgres.py migrate/changeset/databases/sqlite.py migrate/versioning/__init__.py migrate/versioning/api.py migrate/versioning/cfgparse.py migrate/versioning/controlled.py migrate/versioning/exceptions.py migrate/versioning/logengine.py migrate/versioning/pathed.py migrate/versioning/repository.py migrate/versioning/shell.py migrate/versioning/template.py migrate/versioning/unique_instance.py migrate/versioning/version.py migrate/versioning/base/__init__.py migrate/versioning/base/const.py migrate/versioning/base/logger.py migrate/versioning/script/__init__.py migrate/versioning/script/logsql.py migrate/versioning/script/py.py migrate/versioning/script/script.py migrate/versioning/script/sql.py migrate/versioning/templates/__init__.py migrate/versioning/templates/manage.py_tmpl migrate/versioning/templates/repository/__init__.py migrate/versioning/templates/repository/default/README migrate/versioning/templates/repository/default/__init__.py migrate/versioning/templates/repository/default/migrate.cfg migrate/versioning/templates/repository/default/versions/__init__.py migrate/versioning/templates/script/__init__.py migrate/versioning/templates/script/default.py_tmpl migrate/versioning/templates/script/logsql.py_tmpl shell/migrate test/__init__.py test/changeset/__init__.py test/changeset/test_changeset.py test/changeset/test_constraint.py test/fixture/__init__.py test/fixture/base.py test/fixture/database.py test/fixture/pathed.py test/fixture/shell.py test/integrated/__init__.py test/integrated/test_docs.py test/integrated/test_logchangeset.py test/versioning/__init__.py test/versioning/test_cfgparse.py test/versioning/test_controlled.py test/versioning/test_database.py test/versioning/test_logengine.py test/versioning/test_pathed.py test/versioning/test_repository.py test/versioning/test_runchangeset.py test/versioning/test_script.py test/versioning/test_shell.py test/versioning/test_template.py test/versioning/test_unique_instance.py test/versioning/test_version.py PK;N58“×2EGG-INFO/dependency_links.txt PK;N58ãMº——EGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: migrate Version: 0.2.2 Summary: Database schema migration for SQLAlchemy Home-page: http://erosson.com/migrate Author: Evan Rosson Author-email: evan.rosson@gmail.com License: MIT Description: Inspired by Ruby on Rails' migrations, Migrate provides a way to deal with database schema changes in `SQLAlchemy `_ projects. Platform: UNKNOWN PK;N58çDîEGG-INFO/requires.txtsqlalchemy >= 0.3.0devPK;N58nÉ<ŽEGG-INFO/top_level.txtmigrate PKeN58“×2EGG-INFO/not-zip-safe PK,"8h>dÇMMEGG-INFO/scripts/migrate#!/usr/local/bin/python2.3 from migrate.versioning.shell import main main() PK —ƒ5ÉŒmigrate/__init__.pyfrom migrate.run import * PKZN58f±±migrate/run.pyc;ò &dsEc@sdZd„ZdS(s:Each migration script must import everything in this file.cCs%dkl}|dtƒ|iSdS(sjGiven an engine, return the name of the database driving it: 'postgres','mysql','sqlite'... (swarnsBUse engine.name instead; http://erosson.com/migrate/trac/ticket/80N(swarningsswarnsDeprecationWarningsenginesname(sengineswarn((s/build/bdist.darwin-8.0.1-x86/egg/migrate/run.pysdriver s  N(s__doc__sdriver(sdriver((s/build/bdist.darwin-8.0.1-x86/egg/migrate/run.pys?s PK —ƒ5ÑàBZHHmigrate/run.py"""Each migration script must import everything in this file.""" #from sqlalchemy import * #from migrate.changeset import * #from migrate.versioning import logengine #__all__=[ # 'engine', #] # 'migrate_engine' is assigned elsewhere, and used during scripts #migrate_engine = None def driver(engine): """Given an engine, return the name of the database driving it: 'postgres','mysql','sqlite'... """ from warnings import warn warn("Use engine.name instead; http://erosson.com/migrate/trac/ticket/80", DeprecationWarning) return engine.name PKVN58Ö1¤¦¦migrate/__init__.pyc;ò &dsEc@s dkTdS((s*N(s migrate.run(((s4build/bdist.darwin-8.0.1-x86/egg/migrate/__init__.pys?sPKWN58ëá²=ÁÁ!migrate/versioning/exceptions.pyc;ò &dsEc@s¦defd„ƒYZdefd„ƒYZdefd„ƒYZdefd„ƒYZdefd „ƒYZd efd „ƒYZd efd „ƒYZdefd„ƒYZdefd„ƒYZ defd„ƒYZ defd„ƒYZ defd„ƒYZ de fd„ƒYZ de fd„ƒYZdefd„ƒYZdefd„ƒYZd efd!„ƒYZd"efd#„ƒYZd efd$„ƒYZd%S(&sErrorcBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysErrorssApiErrorcBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysApiErrorss KnownErrorcBstZdZRS(sA known error condition(s__name__s __module__s__doc__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pys KnownErrors s UsageErrorcBstZdZRS(s6A known error condition where help should be displayed(s__name__s __module__s__doc__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pys UsageErrors sControlledSchemaErrorcBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysControlledSchemaError ssInvalidVersionErrorcBstZdZRS(sInvalid version number(s__name__s __module__s__doc__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysInvalidVersionError s sDatabaseNotControlledErrorcBstZdZRS(s)Database shouldn't be under vc, but it is(s__name__s __module__s__doc__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysDatabaseNotControlledErrors sDatabaseAlreadyControlledErrorcBstZdZRS(s)Database should be under vc, but it's not(s__name__s __module__s__doc__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysDatabaseAlreadyControlledErrors sWrongRepositoryErrorcBstZdZRS(s<This database is under version control by another repository(s__name__s __module__s__doc__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysWrongRepositoryErrors sNoSuchTableErrorcBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysNoSuchTableErrorss LogSqlErrorcBs tZdZd„Zd„ZRS(s?A SQLError, with a traceback of where that statement was loggedcCs#ti|ƒ||_||_dS(N(s Exceptions__init__sselfssqlerrorsentry(sselfssqlerrorsentry((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pys__init__s  cCsZdt|iƒ}|d7}|diti|iiƒƒ7}|t|iƒ7}|SdS(NsSQL error in statement: %s sTraceback from change script: s(sstrsselfsentrysretsjoins tracebacks format_listssqlerror(sselfsret((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pys__str__s  "(s__name__s __module__s__doc__s__init__s__str__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pys LogSqlErrors  s PathErrorcBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pys PathError%ssPathNotFoundErrorcBstZdZRS(s.A path with no file was required; found a file(s__name__s __module__s__doc__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysPathNotFoundError's sPathFoundErrorcBstZdZRS(s.A path with a file was required; found no file(s__name__s __module__s__doc__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysPathFoundError*s sRepositoryErrorcBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysRepositoryError.ssInvalidRepositoryErrorcBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysInvalidRepositoryError0ss ScriptErrorcBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pys ScriptError3ssInvalidScriptErrorcBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysInvalidScriptError5scBstZRS(N(s__name__s __module__(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pysInvalidVersionError8sN(s ExceptionsErrorsApiErrors KnownErrors UsageErrorsControlledSchemaErrorsInvalidVersionErrorsDatabaseNotControlledErrorsDatabaseAlreadyControlledErrorsWrongRepositoryErrorsNoSuchTableErrors LogSqlErrors PathErrorsPathNotFoundErrorsPathFoundErrorsRepositoryErrorsInvalidRepositoryErrors ScriptErrorsInvalidScriptError(sPathFoundErrorsInvalidRepositoryErrors PathErrors UsageErrorsApiErrors KnownErrorsControlledSchemaErrorsWrongRepositoryErrorsDatabaseNotControlledErrors ScriptErrors LogSqlErrorsDatabaseAlreadyControlledErrorsErrorsInvalidVersionErrorsRepositoryErrorsInvalidScriptErrorsNoSuchTableErrorsPathNotFoundError((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/exceptions.pys?s$ PK —ƒ5migrate/versioning/__init__.pyPK —ƒ5ü)W,,migrate/versioning/template.pyfrom pkg_resources import resource_filename import os,shutil import sys from migrate.versioning.base import * from migrate.versioning import pathed class Packaged(pathed.Pathed): """An object assoc'ed with a Python package""" def __init__(self,pkg): self.pkg = pkg path = self._find_path(pkg) super(Packaged,self).__init__(path) @classmethod def _find_path(cls,pkg): pkg_name, resource_name = pkg.rsplit('.',1) ret = resource_filename(pkg_name,resource_name) return ret class Collection(Packaged): """A collection of templates of a specific type""" _default=None def get_path(self,file): return os.path.join(self.path,str(file)) def get_pkg(self,file): return (self.pkg,str(file)) class RepositoryCollection(Collection): _default='default' class ScriptCollection(Collection): _default='default.py_tmpl' class Template(Packaged): """Finds the paths/packages of various Migrate templates""" _repository='repository' _script='script' _manage='manage.py_tmpl' def __init__(self,pkg): super(Template,self).__init__(pkg) self.repository=RepositoryCollection('.'.join((self.pkg,self._repository))) self.script=ScriptCollection('.'.join((self.pkg,self._script))) def get_item(self,attr,filename=None,as_pkg=None,as_str=None): item = getattr(self,attr) if filename is None: filename = getattr(item,'_default') if as_pkg: ret = item.get_pkg(filename) if as_str: ret = '.'.join(ret) else: ret = item.get_path(filename) return ret def get_repository(self,filename=None,as_pkg=None,as_str=None): return self.get_item('repository',filename,as_pkg,as_str) def get_script(self,filename=None,as_pkg=None,as_str=None): return self.get_item('script',filename,as_pkg,as_str) def manage(self,**k): return (self.pkg,self._manage) template_pkg='migrate.versioning.templates' template=Template(template_pkg) PK —ƒ5^Ë`migrate/versioning/pathed.pyfrom migrate.versioning.base import * from unique_instance import UniqueInstance import os,shutil from migrate.versioning import exceptions class Pathed(UniqueInstance): """A class associated with a path/directory tree""" parent=None @classmethod def _key(cls,path): return str(path) def __init__(self,path): self.path=path if self.__class__.parent is not None: self._init_parent(path) def _init_parent(self,path): """Try to initialize this object's parent, if it has one""" parent_path=self.__class__._parent_path(path) self.parent=self.__class__.parent(parent_path) log.info("Getting parent %r:%r"%(self.__class__.parent,parent_path)) self.parent._init_child(path,self) def _init_child(self,child,path): """Run when a child of this object is initialized Parameters: the child object; the path to this object (its parent) """ pass @classmethod def _parent_path(cls,path): """Fetch the path of this object's parent from this object's path """ # os.path.dirname(), but strip directories like files (like unix basename) # Treat directories like files... if path[-1]=='/': path=path[:-1] ret = os.path.dirname(path) return ret @classmethod def require_notfound(cls,path): """Ensures a given path does not already exist""" if os.path.exists(path): raise exceptions.PathFoundError(path) @classmethod def require_found(cls,path): """Ensures a given path already exists""" if not os.path.exists(path): raise exceptions.PathNotFoundError(path) def __str__(self): return self.path PK —ƒ5æº$¥¥ migrate/versioning/exceptions.py class Error(Exception): pass class ApiError(Error): pass class KnownError(ApiError): """A known error condition""" class UsageError(ApiError): """A known error condition where help should be displayed""" class ControlledSchemaError(Error): pass class InvalidVersionError(ControlledSchemaError): """Invalid version number""" class DatabaseNotControlledError(ControlledSchemaError): """Database shouldn't be under vc, but it is""" class DatabaseAlreadyControlledError(ControlledSchemaError): """Database should be under vc, but it's not""" class WrongRepositoryError(ControlledSchemaError): """This database is under version control by another repository""" class NoSuchTableError(ControlledSchemaError): pass class LogSqlError(Error): """A SQLError, with a traceback of where that statement was logged""" def __init__(self,sqlerror,entry): Exception.__init__(self) self.sqlerror = sqlerror self.entry = entry def __str__(self): ret = "SQL error in statement: \n%s\n"%(str(self.entry)) ret += "Traceback from change script:\n" ret += ''.join(traceback.format_list(self.entry.traceback)) ret += str(self.sqlerror) return ret class PathError(Error): pass class PathNotFoundError(PathError): """A path with no file was required; found a file""" pass class PathFoundError(PathError): """A path with a file was required; found no file""" pass class RepositoryError(Error): pass class InvalidRepositoryError(RepositoryError): pass class ScriptError(Error): pass class InvalidScriptError(ScriptError): pass class InvalidVersionError(Error): pass PK —ƒ5Õ¼–†ªª migrate/versioning/controlled.pyfrom sqlalchemy import * import sqlalchemy from base import * from migrate.versioning.repository import Repository from migrate.versioning.version import VerNum from migrate.versioning import exceptions class ControlledSchema(object): """A database under version control""" #def __init__(self,engine,repository=None): def __init__(self,engine,repository): if type(repository) is str: repository=Repository(repository) self.engine = engine self.repository = repository self.meta=BoundMetaData(engine) #if self.repository is None: # self._get_repository() self._load() def __eq__(self,other): return (self.repository is other.repository \ and self.version == other.version) def _load(self): """Load controlled schema version info from DB""" tname = self.repository.version_table self.meta=BoundMetaData(self.engine) if not hasattr(self,'table') or self.table is None: try: self.table=Table(tname,self.meta,autoload=True) except (exceptions.NoSuchTableError): raise exceptions.DatabaseNotControlledError(tname) # TODO?: verify that the table is correct (# cols, etc.) result = self.engine.execute(self.table.select(),) data = list(result)[0] # TODO?: exception if row count is bad # TODO: check repository id, exception if incorrect self.version = data['version'] def _get_repository(self): """Given a database engine, try to guess the repository""" # TODO: no guessing yet; for now, a repository must be supplied raise NotImplementedError() @classmethod def create(cls,engine,repository,version=None): """Declare a database to be under a repository's version control""" # Confirm that the version # is valid: positive, integer, exists in repos if type(repository) is str: repository=Repository(repository) version = cls._validate_version(repository,version) table=cls._create_table_version(engine,repository,version) # TODO: history table # Load repository information and return return cls(engine,repository) @classmethod def _validate_version(cls,repository,version): """Ensures this is a valid version number for this repository If invalid, raises cls.InvalidVersionError Returns a valid version number """ if version is None: version=0 try: version = VerNum(version) # raises valueerror if version < 0 or version > repository.latest: raise ValueError() except ValueError: raise exceptions.InvalidVersionError(version) return version @classmethod def _create_table_version(cls,engine,repository,version): """Creates the versioning table in a database""" # Create tables tname = repository.version_table meta=BoundMetaData(engine) try: table=Table(tname,meta, #Column('repository_id',String,primary_key=True), # MySQL needs a length Column('repository_id',String(255),primary_key=True), Column('repository_path',String), Column('version',Integer), ) table.create() except (sqlalchemy.exceptions.ArgumentError,sqlalchemy.exceptions.SQLError): # The table already exists raise exceptions.DatabaseAlreadyControlledError() # Insert data engine.execute(table.insert(),repository_id=repository.id, repository_path=repository.path,version=int(version)) return table def drop(self): """Remove version control from a database""" try: self.table.drop() except (sqlalchemy.exceptions.SQLError): raise exceptions.DatabaseNotControlledError(str(self.table)) def _engine_db(self,engine): """Returns the database name of an engine - 'postgres','sqlite'...""" # TODO: This is a bit of a hack... return str(engine.dialect.__module__).split('.')[-1] def changeset(self,version=None): database = self._engine_db(self.engine) start_ver = self.version changeset = self.repository.changeset(database,start_ver,version) return changeset def runchange(self,ver,change,step): startver = ver endver = ver + step # Current database version must be correct! Don't run if corrupt! if self.version != startver: raise exceptions.InvalidVersionError("%s is not %s"%(self.version,startver)) # Run the change change.run(self.engine,step) # Update/refresh database version update = self.table.update(self.table.c.version == int(startver)) self.engine.execute(update, version=int(endver)) self._load() def upgrade(self,version=None): """Upgrade (or downgrade) to a specified version, or latest version""" changeset = self.changeset(version) for ver,change in changeset: self.runchange(ver,change,changeset.step) PK —ƒ5 ­×%%migrate/versioning/api.py"""An external API to the versioning system Used by the shell utility; could also be used by other scripts """ from migrate.versioning.base import * from migrate.versioning.repository import * from migrate.versioning.repository import manage as repository_manage from migrate.versioning.controlled import * from migrate.versioning import exceptions import script as script_ # Conflicts with a command import sys import stat import inspect __all__=[#'KnownError','UsageError', 'help', 'create', 'script', 'commit', 'version', 'source', 'version_control', 'db_version', 'upgrade', 'downgrade', 'drop_version_control', 'manage', 'test', ] def help(cmd=None,**opts): """%prog help COMMAND Displays help on a given command. """ if cmd is None: raise exceptions.UsageError(None) try: func = globals()[cmd] except: raise exceptions.UsageError("'%s' isn't a valid command. Try 'help COMMAND'"%cmd) ret = func.__doc__ if sys.argv[0]: ret = ret.replace('%prog',sys.argv[0]) return ret def create(repository,name,**opts): """%prog create REPOSITORY_PATH NAME [--table=TABLE] Create an empty repository at the specified path. You can specify the version_table to be used; by default, it is '_version'. This table is created in all version-controlled databases. """ try: rep=Repository.create(repository,name,**opts) except exceptions.PathFoundError,e: raise exceptions.KnownError("The path %s already exists"%e.args[0]) def script(path,**opts): """%prog script PATH Create an empty change script at the specified path. """ try: script_.PythonFile.create(path,**opts) except exceptions.PathFoundError,e: raise exceptions.KnownError("The path %s already exists"%e.args[0]) def commit(script,repository,database=None,operation=None,version=None,**opts): """%prog commit SCRIPT_PATH.py REPOSITORY_PATH [VERSION] %prog commit SCRIPT_PATH.sql REPOSITORY_PATH DATABASE OPERATION [VERSION] Commit a script to this repository. The committed script is added to the repository, and the file disappears. Once a script has been committed, you can use it to upgrade a database with the 'upgrade' command. If a version is given, that version will be replaced instead of creating a new version. Normally, when writing change scripts in Python, you'll use the first form of this command (DATABASE and OPERATION aren't specified). If you write change scripts as .sql files, you'll need to specify DATABASE ('postgres', 'mysql', 'oracle', 'sqlite'...) and OPERATION ('upgrade' or 'downgrade'). You may commit multiple .sql files under the same version to complete functionality for a particular version:: %prog commit upgrade.postgres.sql /repository/path postgres upgrade 1 %prog commit downgrade.postgres.sql /repository/path postgres downgrade 1 %prog commit upgrade.sqlite.sql /repository/path sqlite upgrade 1 %prog commit downgrade.sqlite.sql /repository/path sqlite downgrade 1 [etc...] """ if (database is not None) and (operation is None) and (version is None): # Version was supplied as a positional version = database database = None repos = Repository(repository) repos.commit(script,version,database=database,operation=operation) def test(script,repository,url=None,**opts): """%prog test SCRIPT_PATH REPOSITORY_PATH URL [VERSION] """ engine=create_engine(url) controlled=ControlledSchema(engine,repository) script = script_.PythonFile(script) # Upgrade print "Upgrading...", try: script.run(engine,1) except: print "ERROR" raise print "done" print "Downgrading...", try: script.run(engine,-1) except: print "ERROR" raise print "done" print "Success" def version(repository,**opts): """%prog version REPOSITORY_PATH Display the latest version available in a repository. """ repos=Repository(repository) return repos.latest def source(version,dest=None,repository=None,**opts): """%prog source VERSION [DESTINATION] --repository=REPOSITORY_PATH Display the Python code for a particular version in this repository. Save it to the file at DESTINATION or, if omitted, send to stdout. """ if repository is None: raise exceptions.UsageError("A repository must be specified") repos=Repository(repository) ret=repos.version(version).script().source() if dest is not None: dest=open(dest,'w') dest.write(ret) ret=None return ret def version_control(url,repository,version=None,**opts): """%prog version_control URL REPOSITORY_PATH [VERSION] Mark a database as under this repository's version control. Once a database is under version control, schema changes should only be done via change scripts in this repository. This creates the table version_table in the database. The url should be any valid SQLAlchemy connection string. By default, the database begins at version 0 and is assumed to be empty. If the database is not empty, you may specify a version at which to begin instead. No attempt is made to verify this version's correctness - the database schema is expected to be identical to what it would be if the database were created from scratch. """ engine=create_engine(url) ControlledSchema.create(engine,repository,version) def db_version(url,repository,**opts): """%prog db_version URL REPOSITORY_PATH Show the current version of the repository with the given connection string, under version control of the specified repository. The url should be any valid SQLAlchemy connection string. """ engine=create_engine(url) controlled=ControlledSchema(engine,repository) return controlled.version def upgrade(url,repository,version=None,**opts): """%prog upgrade URL REPOSITORY_PATH [VERSION] [--preview_py|--preview_sql] Upgrade a database to a later version. This runs the upgrade() function defined in your change scripts. By default, the database is updated to the latest available version. You may specify a version instead, if you wish. You may preview the Python or SQL code to be executed, rather than actually executing it, using the appropriate 'preview' option. """ err = "Cannot upgrade a database of version %s to version %s. "\ "Try 'downgrade' instead." return _migrate(url,repository,version,upgrade=True,err=err,**opts) def downgrade(url,repository,version,**opts): """%prog downgrade URL REPOSITORY_PATH VERSION [--preview_py|--preview_sql] Downgrade a database to an earlier version. This is the reverse of upgrade; this runs the downgrade() function defined in your change scripts. You may preview the Python or SQL code to be executed, rather than actually executing it, using the appropriate 'preview' option. """ err = "Cannot downgrade a database of version %s to version %s. "\ "Try 'upgrade' instead." return _migrate(url,repository,version,upgrade=False,err=err,**opts) def _migrate(url,repository,version,upgrade,err,**opts): engine=create_engine(url) controlled=ControlledSchema(engine,repository) version = _migrate_version(controlled,version,upgrade,err) changeset = controlled.changeset(version) for ver,change in changeset: nextver = ver + changeset.step print '%s -> %s... '%(ver,nextver), if opts.get('preview_sql'): print print change.log elif opts.get('preview_py'): source_ver = max(ver,nextver) module = controlled.repository.version(source_ver).script().module funcname = upgrade and "upgrade" or "downgrade" func = getattr(module,funcname) print print inspect.getsource(module.upgrade) else: controlled.runchange(ver,change,changeset.step) print 'done' def _migrate_version(controlled,version,upgrade,err): if version is None: return version # Version is specified: ensure we're upgrading in the right direction # (current version < target version for upgrading; reverse for down) version = VerNum(version) cur = controlled.version if upgrade is not None: if upgrade: direction = cur <= version else: direction = cur >= version if not direction: raise exceptions.KnownError(err%(cur,version)) return version def drop_version_control(url,repository,**opts): """%prog drop_version_control URL REPOSITORY_PATH Removes version control from a database. """ engine=create_engine(url) controlled=ControlledSchema(engine,repository) controlled.drop() def manage(file,**opts): """%prog manage FILENAME VARIABLES... Creates a script that runs Migrate with a set of default values. For example:: %prog manage manage.py --repository=/path/to/repository --url=sqlite:///project.db would create the script manage.py. The following two commands would then have exactly the same results:: python manage.py version %prog version --repository=/path/to/repository """ return repository_manage(file,**opts) PKWN58ÕëzѪªmigrate/versioning/shell.pyc;ò &dsEc @s dZdkZdkTdklZlZdklZlZdk Z e dei dei dei deid eiƒad „Zeƒd efd „ƒYZd d„Ze d dddddƒad„Zd„Zd„Zed„Zedjo eƒndS(sThe migrate command-line tool. N(s*(s OptionParsersValues(sapis exceptionsssscisvcsdbvsvcCs1x*tiƒD]\}}tt||ƒq WdS(N(saliass iteritemsskeysvalssetattrsapi(svalskey((s<build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/shell.pys alias_setups sShellUsageErrorcBstZed„ZRS(NcCsd}|iddddƒ}ttiƒ}|iƒditd„|ƒƒ}||}y|idt i dƒ}Wnt j onX|idtj o6|dt|idƒ7}|tjo d }qÛn|tjo d}nt||ƒdS( Ns%%prog COMMAND ... Available commands: %s Enter "%%prog help COMMAND" for information on a particular command. s s icCsd|S(Ns (sx(sx((s<build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/shell.pys!ss%progis Error: %s i(susagesreplaceslistsapis__all__scommandsssortsjoinsmapsmessagessyssargvs IndexErrorsselfsargssNonesstrsexitcodesdie(sselfsexitcodescommandssusagesmessage((s<build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/shell.pysdies"     (s__name__s __module__sNonesdie(((s<build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/shell.pysShellUsageErrorsicCsG|tj o$tii|ƒtiidƒntt|ƒƒ‚dS(Ns (smessagesNonessyssstderrswrites SystemExitsintsexitcode(smessagesexitcode((s<build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/shell.pysdie0s sverbosesdsdebugsfsforcecCsA|iddƒ}t|ƒdjo|dtg}n|SdS(Ns=ii(sargssplitsretslensTrue(sargsret((s<build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/shell.pyskwparse<scCsÔ|idƒot|dƒ\}}n|idƒoOyti|ƒ}Wn#tj ot d|ƒ‚nXt|ƒ\}}n>|}y|i dƒ}Wn!t j o}t dƒ‚nX||fSdS(Ns--is-sInvalid argument: %sisToo many arguments to command(sargs startswithskwparseskwsvalskwmapsgetspargsKeyErrorsShellUsageErrorsargnamesspops IndexErrorse(sargsargnamesspargsesvalskw((s<build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/shell.pys parse_argCscOsvt|ƒ}y|idƒ} Wntj ottƒ‚nX| djp | djo d} ntt| tƒ}|tjp | i dƒotd| ƒ‚nt i |ƒ\}} } } t|ƒ}x-|D]%}t||ƒ\} }||| y, keys are version x. Sorted.""" ret = super(Changeset,self).keys() # Reverse order if downgrading ret.sort(reverse=(self.step < 1)) return ret def values(self): return [self[k] for k in self.keys()] def items(self): return zip(self.keys(),self.values()) def add(self,change): key = self.end self.end += self.step self[key] = change def run(self,*p,**k): for version,script in self: script.run(*p,**k) class Repository(Pathed): """A project's change script repository""" # Configuration file, inside repository _config='migrate.cfg' # Version information, inside repository _versions='versions' def __init__(self,path): log.info('Loading repository %s...'%path) self.verify(path) super(Repository,self).__init__(path) self.config=Config(os.path.join(self.path,self._config)) self.versions=version.Collection(os.path.join(self.path,self._versions)) log.info('Repository %s loaded successfully'%path) log.debug('Config: %r'%self.config.to_dict()) @classmethod def verify(cls,path): """Ensure the target path is a valid repository Throws InvalidRepositoryError if not """ # Ensure the existance of required files try: cls.require_found(path) cls.require_found(os.path.join(path,cls._config)) cls.require_found(os.path.join(path,cls._versions)) except exceptions.PathNotFoundError,e: raise exceptions.InvalidRepositoryError(path) @classmethod def prepare_config(cls,pkg,rsrc,name,**opts): """Prepare a project configuration file for a new project""" # Prepare opts defaults=dict( version_table='migrate_version', repository_id=name, required_dbs=[], ) for key,val in defaults.iteritems(): if (key not in opts) or (opts[key] is None): opts[key]=val tmpl = resource_string(pkg,rsrc) ret = string.Template(tmpl).substitute(opts) return ret @classmethod def create(cls,path,name,**opts): """Create a repository at a specified path""" cls.require_notfound(path) pkg,rsrc = template.get_repository(as_pkg=True) tmplpkg = '.'.join((pkg,rsrc)) tmplfile = resource_filename(pkg,rsrc) config_text = cls.prepare_config(tmplpkg,cls._config,name,**opts) # Create repository try: shutil.copytree(tmplfile,path) # Edit config defaults fd = open(os.path.join(path,cls._config),'w') fd.write(config_text) fd.close() # Create a management script manager = os.path.join(path,'manage.py') manage(manager,repository=path) except: log.error("There was an error creating your repository") return cls(path) def commit(self,*p,**k): reqd = self.config.get('db_settings','required_dbs') return self.versions.commit(required=reqd,*p,**k) latest=property(lambda self: self.versions.latest) version_table=property(lambda self: self.config.get('db_settings','version_table')) id=property(lambda self: self.config.get('db_settings','repository_id')) def version(self,*p,**k): return self.versions.version(*p,**k) @classmethod def clear(cls): Pathed.clear(cls) version.Collection.clear() def changeset(self,database,start,end=None): """Create a changeset to migrate this dbms from ver. start to end/latest """ start = VerNum(start) if end is None: end = self.latest else: end = VerNum(end) if start <= end: step = 1 range_mod = 1 op = 'upgrade' else: step = -1 range_mod = 0 op = 'downgrade' versions = range(start+range_mod,end+range_mod,step) #changes = [self.version(v).script(database,op).log for v in versions] changes = [self.version(v).script(database,op) for v in versions] ret = Changeset(start,step=step,*changes) return ret def manage(file,**opts): """Create a project management script""" pkg,rsrc = template.manage(as_pkg=True) tmpl = resource_string(pkg,rsrc) vars = ",".join(["%s='%s'"%vars for vars in opts.iteritems()]) result = tmpl%dict(defaults=vars) fd = open(file,'w') fd.write(result) fd.close() PK —ƒ5.¹y%ññmigrate/versioning/shell.py"""The migrate command-line tool. """ import sys from migrate.versioning.base import * from optparse import OptionParser,Values from migrate.versioning import api,exceptions import inspect alias = dict( s=api.script, ci=api.commit, vc=api.version_control, dbv=api.db_version, v=api.version, ) def alias_setup(): global alias for key,val in alias.iteritems(): setattr(api,key,val) alias_setup() class ShellUsageError(Exception): def die(self,exitcode=None): usage="""%%prog COMMAND ... Available commands: %s Enter "%%prog help COMMAND" for information on a particular command. """ usage = usage.replace("\n"+" "*8,"\n") commands = list(api.__all__) commands.sort() commands = '\n'.join(map((lambda x:'\t'+x),commands)) message = usage%commands try: message = message.replace('%prog',sys.argv[0]) except IndexError: pass if self.args[0] is not None: message += "\nError: %s\n"%str(self.args[0]) if exitcode is None: exitcode = 1 if exitcode is None: exitcode = 0 die(message,exitcode) def die(message,exitcode=1): if message is not None: sys.stderr.write(message) sys.stderr.write("\n") raise SystemExit(int(exitcode)) kwmap = dict( v='verbose', d='debug', f='force', ) def kwparse(arg): ret = arg.split('=',1) if len(ret) == 1: # No value specified (--kw, not --kw=stuff): use True ret = [ret[0],True] return ret def parse_arg(arg,argnames): global kwmap if arg.startswith('--'): # Keyword-argument; either --keyword or --keyword=value kw,val = kwparse(arg[2:]) elif arg.startswith('-'): # Short form of a keyword-argument; map it to a keyword try: parg = kwmap.get(arg) except KeyError: raise ShellUsageError("Invalid argument: %s"%arg) kw,val = kwparse(parg) else: # Simple positional parameter val = arg try: kw = argnames.pop(0) except IndexError,e: raise ShellUsageError("Too many arguments to command") return kw,val def parse_args(*args,**kwargs): """Map positional arguments to keyword-args""" args=list(args) try: cmdname = args.pop(0) except IndexError: # No command specified: no error message; just show usage raise ShellUsageError(None) # Special cases: -h and --help should act like 'help' if cmdname == '-h' or cmdname == '--help': cmdname = 'help' cmdfunc = getattr(api,cmdname,None) if cmdfunc is None or cmdname.startswith('_'): raise ShellUsageError("Invalid command %s"%cmdname) argnames, p,k, defaults = inspect.getargspec(cmdfunc) argnames_orig = list(argnames) for arg in args: kw,val = parse_arg(arg,argnames) kwargs[kw] = val if defaults is not None: num_defaults = len(defaults) else: num_defaults = 0 req_argnames = argnames_orig[:len(argnames_orig)-num_defaults] for name in req_argnames: if name not in kwargs: raise ShellUsageError("Too few arguments: %s not specified"%name) return cmdfunc,kwargs def main(argv=None,**kwargs): if argv is None: argv = list(sys.argv[1:]) try: command, kwargs = parse_args(*argv,**kwargs) except ShellUsageError,e: e.die() try: ret = command(**kwargs) if ret is not None: print ret except exceptions.UsageError,e: e = ShellUsageError(e.args[0]) e.die() except exceptions.KnownError,e: die(e.args[0]) if __name__=="__main__": main() PK —ƒ5ðFO{3'3'migrate/versioning/version.pyfrom migrate.versioning.pathed import * from migrate.versioning import exceptions import script class VerNum(object): """A version number""" _instances=dict() def __new__(cls,value): val=str(value) if val not in cls._instances: cls._instances[val] = super(VerNum,cls).__new__(cls,value) ret = cls._instances[val] return ret def __init__(self,value): self.value=str(int(value)) if self < 0: raise ValueError("Version number cannot be negative") def __repr__(self): return str(self.value) def __str__(self): return str(self.value) def __int__(self): return int(self.value) def __add__(self,value): ret=int(self)+int(value) return VerNum(ret) def __sub__(self,value): return self+(int(value)*-1) def __cmp__(self,value): return int(self)-int(value) class Collection(Pathed): """A collection of versioning scripts in a repository""" def __init__(self,path): super(Collection,self).__init__(path) self.versions=dict() ver=self.latest=VerNum(1) vers=os.listdir(path) # This runs up to the latest *complete* version; stops when one's missing while str(ver) in vers: verpath=self.version_path(ver) self.versions[ver]=Version(verpath) ver+=1 self.latest=ver-1 def version_path(self,ver): return os.path.join(self.path,str(ver)) def version(self,vernum=None): if vernum is None: vernum = self.latest return self.versions[VerNum(vernum)] def commit(self,path,ver=None,*p,**k): """Commit a script to this collection of scripts This compiles the script into a group of logsql files If there's an error compiling the script, the commit is cancelled """ maxver = self.latest+1 if ver is None: ver = maxver # Ver must be valid: can't upgrade past the next version # No change scripts exist for 0 (even though it's a valid version) if ver > maxver or ver == 0: raise exceptions.InvalidVersionError() verpath = self.version_path(ver) tmpname = None try: # If replacing an old version, copy it in case it gets trashed if os.path.exists(verpath): tmpname = os.path.join(os.path.split(verpath)[0],"%s_tmp"%ver) shutil.copytree(verpath,tmpname) version = Version(verpath) else: # Create version folder version = Version.create(verpath) self.versions[ver] = version # Commit the individual script script = version.commit(path,*p,**k) except: # Can't leave the folder created above... shutil.rmtree(verpath) # Rollback if a version already existed above if tmpname is not None: shutil.move(tmpname,verpath) raise # Success: mark latest; delete old version if tmpname is not None: shutil.rmtree(tmpname) self.latest = ver @classmethod def clear(cls): Pathed.clear(cls) Version.clear() class extensions: """A namespace for file extensions""" py='py' sql='sql' logsql='logsql' class Version(Pathed): """A single version in a repository File must be a directory with an integer name. logsql files are named with the version, DBMS, and operation (up or down). Example:: 1/ 1.py 1.postgres.up.logsql 1.postgres.down.logsql 1.sqlite.up.logsql 1.sqlite.down.logsql ... """ def __init__(self,path): super(Version,self).__init__(path) # Version must be numeric try: self.version=VerNum(os.path.basename(path)) except: raise exceptions.InvalidVersionError(path) # Collect scripts in this folder self.logsql = dict() self.sql = dict() self.python = None try: for script in os.listdir(path): self._add_script(os.path.join(path,script)) except: raise exceptions.InvalidVersionError(path) def script(self,database=None,operation=None): #if database is None and operation is None: # return self._script_py() # Try to return a logsql file; if none exists, return a python file #print database,operation,self.sql try: ret = self._script_logsql(database,operation) except KeyError: try: ret = self._script_sql(database,operation) except KeyError: ret = self._script_py() assert ret is not None return ret def _script_py(self): return self.python def _script_logsql(self,database,operation): from warnings import warn warn("logsql is deprecated: http://erosson.com/migrate/trac/ticket/75", DeprecationWarning) return self.logsql[database][operation] def _script_sql(self,database,operation): return self.sql[database][operation] @classmethod def create(cls,path): os.mkdir(path) try: ret=cls(path) except: os.rmdir(path) raise return ret def _add_script(self,path): if path.endswith(extensions.py): self._add_script_py(path) elif path.endswith(extensions.logsql): self._add_script_logsql(path) elif path.endswith(extensions.sql): self._add_script_sql(path) def _add_script_logsql(self,path): try: version,dbms,op,ext=path.split('.',3) except: raise exceptions.ScriptError("Invalid logsql script name %s"%path) # File the script into a dictionary dbmses = self.logsql if dbms not in dbmses: dbmses[dbms] = dict() ops = dbmses[dbms] ops[op] = script.LogsqlFile(path) def _add_script_sql(self,path): try: version,dbms,op,ext=path.split('.',3) except: raise exceptions.ScriptError("Invalid sql script name %s"%path) # File the script into a dictionary dbmses = self.sql if dbms not in dbmses: dbmses[dbms] = dict() ops = dbmses[dbms] ops[op] = script.SqlFile(path) def _add_script_py(self,path): self.python = script.PythonFile(path) def _rm_ignore(self,path): """Try to remove a path; ignore failure""" try: os.remove(path) except OSError: pass def _compile_one(self,sourcefile,db,op,path,required=None): """Given a valid python fileobject, create a single logsql file On failure, return None; success, return the path of the new file """ if required is None: required = () try: try: logsql = sourcefile.compile(db,op,path) self._add_script(logsql.path) except: # Always remove the bad file; but we might do more processing self._rm_ignore(path) raise except (exceptions.ScriptError,NotImplementedError): # Some compile failures are ok: we don't need all DBs if db in required: raise def _compile(self,path_py,required=None): """Given a valid Python file, create all possible logsql files""" # This must be done before moving the Python file: dependencies, errors sourcefile = script.PythonFile(path_py) # Should we compile this file at all? if not sourcefile.logsql: return # Yes, logsql is used from warnings import warn warn("logsql is deprecated: http://erosson.com/migrate/trac/ticket/75", DeprecationWarning) path_tmpl = os.path.join(self.path,'%s.%%s.%%s.%s' %(self.version,extensions.logsql)) paths = [] # all paths compiled so far try: for db in databases: for op in operations.keys(): path = path_tmpl%(db,op) paths.append(path) self._compile_one(sourcefile,db,op,path,required=required) except: # Delete all other created files on failure for path in paths: self._rm_ignore(path) raise def commit(self,path,database=None,operation=None,required=None): if (database is not None) and (operation is not None): return self._commit_sql(path,database,operation) return self._commit_py(path,required) def _commit_sql(self,path,database,operation): if not path.endswith(extensions.sql): msg = "Bad file extension: should end with %s"%extensions.sql raise exceptions.ScriptError(msg) dest=os.path.join(self.path,'%s.%s.%s.%s'%( str(self.version),str(database),str(operation),extensions.sql)) # Move the committed py script to this version's folder shutil.move(path,dest) self._add_script(dest) def _commit_py(self,path_py,required=None): if (not os.path.exists(path_py)) or (not os.path.isfile(path_py)): raise exceptions.InvalidVersionError(path_py) dest = os.path.join(self.path,'%s.%s'%(str(self.version),extensions.py)) # Create logsql files, if needed self._compile(path_py,required=required) # Move the committed py script to this version's folder shutil.move(path_py,dest) self._add_script(dest) # Also delete the .pyc file, if it exists path_pyc = path_py+'c' if os.path.exists(path_pyc): self._rm_ignore(path_pyc) PK —ƒ5#×b€€%migrate/versioning/unique_instance.pyfrom migrate.versioning.base import * class UniqueInstance(object): """A class whose instances have a unique identifier of some sort No two instances with the same unique ID should exist - if we try to create a second instance, the first should be returned. """ # _instances[class][instance] _instances=dict() def __new__(cls,*p,**k): instances = cls._instances clskey = str(cls) if clskey not in instances: instances[clskey] = dict() instances = instances[clskey] key = cls._key(*p,**k) if key not in instances: instances[key] = super(UniqueInstance,cls).__new__(cls,*p,**k) self = instances[key] return self @classmethod def _key(cls,*p,**k): """Given a unique identifier, return a dictionary key This should be overridden by child classes, to specify which parameters should determine an object's uniqueness """ raise NotImplementedError(\ 'UniqueInstance._key must be overridden by the child class') #ret = str(p)+str(k) #return ret @classmethod def clear(cls,cls2=None): # Allow cls.clear() as well as UniqueInstance.clear(cls) if cls2 is not None: cls=cls2 if str(cls) in UniqueInstance._instances: del UniqueInstance._instances[str(cls)] PKXN58‘O°”""migrate/versioning/cfgparse.pyc;ò &dsEc@sWdkTdklZdklZdefd„ƒYZdeiefd„ƒYZdS((s*(spathed(s ConfigParsersParsercBstZdZed„ZRS(sA project configuration filecCs |iSdS(s5It's easier to access config values like dictionariesN(sselfs _sections(sselfssections((s?build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/cfgparse.pysto_dict s(s__name__s __module__s__doc__sNonesto_dict(((s?build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/cfgparse.pysParsers sConfigcBstZd„ZRS(NcOsD|i|ƒtii||ƒti|||Ž|i |ƒdS(s'Confirm the config file exists; read itN( sselfs require_foundspathspathedsPatheds__init__sParserspsksread(sselfspathspsk((s?build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/cfgparse.pys__init__s  (s__name__s __module__s__init__(((s?build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/cfgparse.pysConfig sN(smigrate.versioning.basesmigrate.versioningspatheds ConfigParsersParsersPathedsConfig(sConfigsParserspatheds ConfigParser((s?build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/cfgparse.pys?s  PKVN58&’ž$migrate/versioning/__init__.pyc;ò &dsEc@sdS(N((((s?build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/__init__.pys?sPKWN58{¥j‰1‰1migrate/versioning/api.pyc;ò &dsEc @s,dZdkTdkTdklZdkTdklZdkZ dk Z dk Z dk Z ddddd d d d d ddddg Z ed„Zd„Zd„Zeeed„Zed„Zd„Zeed„Zed„Zd„Zed„Zd„Zd„Zd„Zd„Zd „ZdS(!shAn external API to the versioning system Used by the shell utility; could also be used by other scripts (s*(smanage(s exceptionsNshelpscreatesscriptscommitsversionssourcesversion_controls db_versionsupgrades downgradesdrop_version_controlsmanagestestcKsŠ|tjotitƒ‚nytƒ|}Wntid|ƒ‚nX|i}ti do|i dti dƒ}n|SdS(s>%prog help COMMAND Displays help on a given command. s.'%s' isn't a valid command. Try 'help COMMAND'is%progN( scmdsNones exceptionss UsageErrorsglobalssfuncs__doc__sretssyssargvsreplace(scmdsoptssretsfunc((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pyshelps  cKsRyti|||}Wn2tij o#}ti d|i dƒ‚nXdS(sý%prog create REPOSITORY_PATH NAME [--table=TABLE] Create an empty repository at the specified path. You can specify the version_table to be used; by default, it is '_version'. This table is created in all version-controlled databases. sThe path %s already existsiN( s Repositoryscreates repositorysnamesoptssreps exceptionssPathFoundErrorses KnownErrorsargs(s repositorysnamesoptssesrep((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pyscreate.s cKsPytii||Wn2tij o#}tid|i dƒ‚nXdS(sQ%prog script PATH Create an empty change script at the specified path. sThe path %s already existsiN( sscript_s PythonFilescreatespathsoptss exceptionssPathFoundErrorses KnownErrorsargs(spathsoptsse((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pysscript;s cKsc|tj o|tjo |tjo|}t}nt|ƒ}|i||d|d|ƒdS(sÇ%prog commit SCRIPT_PATH.py REPOSITORY_PATH [VERSION] %prog commit SCRIPT_PATH.sql REPOSITORY_PATH DATABASE OPERATION [VERSION] Commit a script to this repository. The committed script is added to the repository, and the file disappears. Once a script has been committed, you can use it to upgrade a database with the 'upgrade' command. If a version is given, that version will be replaced instead of creating a new version. Normally, when writing change scripts in Python, you'll use the first form of this command (DATABASE and OPERATION aren't specified). If you write change scripts as .sql files, you'll need to specify DATABASE ('postgres', 'mysql', 'oracle', 'sqlite'...) and OPERATION ('upgrade' or 'downgrade'). You may commit multiple .sql files under the same version to complete functionality for a particular version:: %prog commit upgrade.postgres.sql /repository/path postgres upgrade 1 %prog commit downgrade.postgres.sql /repository/path postgres downgrade 1 %prog commit upgrade.sqlite.sql /repository/path sqlite upgrade 1 %prog commit downgrade.sqlite.sql /repository/path sqlite downgrade 1 [etc...] sdatabases operationN( sdatabasesNones operationsversions Repositorys repositorysreposscommitsscript(sscripts repositorysdatabases operationsversionsoptssrepos((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pyscommitEs '  cKs‘t|ƒ}t||ƒ}ti|ƒ}dGy|i |dƒWndGH‚nXdGHdGy|i |dƒWndGH‚nXdGHdGHdS( s9%prog test SCRIPT_PATH REPOSITORY_PATH URL [VERSION] s Upgrading...isERRORsdonesDowngrading...iÿÿÿÿsSuccessN( s create_enginesurlsenginesControlledSchemas repositorys controlledsscript_s PythonFilesscriptsrun(sscripts repositorysurlsoptssengines controlled((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pystesths& cKst|ƒ}|iSdS(s]%prog version REPOSITORY_PATH Display the latest version available in a repository. N(s Repositorys repositorysreposslatest(s repositorysoptssrepos((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pysversion€s cKs‚|tjotidƒ‚nt|ƒ}|i|ƒiƒiƒ}|tj o&t |dƒ}|i |ƒt}n|SdS(sÖ%prog source VERSION [DESTINATION] --repository=REPOSITORY_PATH Display the Python code for a particular version in this repository. Save it to the file at DESTINATION or, if omitted, send to stdout. sA repository must be specifiedswN( s repositorysNones exceptionss UsageErrors Repositorysrepossversionsscriptssourcesretsdestsopenswrite(sversionsdests repositorysoptssrepossret((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pyssourceˆs     cKs#t|ƒ}ti|||ƒdS(sË%prog version_control URL REPOSITORY_PATH [VERSION] Mark a database as under this repository's version control. Once a database is under version control, schema changes should only be done via change scripts in this repository. This creates the table version_table in the database. The url should be any valid SQLAlchemy connection string. By default, the database begins at version 0 and is assumed to be empty. If the database is not empty, you may specify a version at which to begin instead. No attempt is made to verify this version's correctness - the database schema is expected to be identical to what it would be if the database were created from scratch. N(s create_enginesurlsenginesControlledSchemascreates repositorysversion(surls repositorysversionsoptssengine((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pysversion_control˜s cKs&t|ƒ}t||ƒ}|iSdS(sò%prog db_version URL REPOSITORY_PATH Show the current version of the repository with the given connection string, under version control of the specified repository. The url should be any valid SQLAlchemy connection string. N(s create_enginesurlsenginesControlledSchemas repositorys controlledsversion(surls repositorysoptssengines controlled((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pys db_version¬s c Ks)d}t|||dtd||SdS(sÈ%prog upgrade URL REPOSITORY_PATH [VERSION] [--preview_py|--preview_sql] Upgrade a database to a later version. This runs the upgrade() function defined in your change scripts. By default, the database is updated to the latest available version. You may specify a version instead, if you wish. You may preview the Python or SQL code to be executed, rather than actually executing it, using the appropriate 'preview' option. sOCannot upgrade a database of version %s to version %s. Try 'downgrade' instead.supgradeserrN(serrs_migratesurls repositorysversionsTruesopts(surls repositorysversionsoptsserr((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pysupgrade¸s c Ks)d}t|||dtd||SdS(st%prog downgrade URL REPOSITORY_PATH VERSION [--preview_py|--preview_sql] Downgrade a database to an earlier version. This is the reverse of upgrade; this runs the downgrade() function defined in your change scripts. You may preview the Python or SQL code to be executed, rather than actually executing it, using the appropriate 'preview' option. sOCannot downgrade a database of version %s to version %s. Try 'upgrade' instead.supgradeserrN(serrs_migratesurls repositorysversionsFalsesopts(surls repositorysversionsoptsserr((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pys downgradeÈs cKs t|ƒ} t| |ƒ} t| |||ƒ}| i |ƒ}xÚ|D]Ò\}} ||i }d||fG|idƒo H| iGHqF|idƒoct||ƒ}| ii|ƒiƒi}|odpd} t|| ƒ} Hti|iƒGHqF| i|| |i ƒdGHqFWdS(Ns %s -> %s... s preview_sqls preview_pysupgrades downgradesdone(s create_enginesurlsenginesControlledSchemas repositorys controlleds_migrate_versionsversionsupgradeserrs changesetsverschangesstepsnextversoptssgetslogsmaxs source_versscriptsmodulesfuncnamesgetattrsfuncsinspects getsources runchange(surls repositorysversionsupgradeserrsoptss changesetsmodulesversengines controlledsfuncschangesfuncnamesnextvers source_ver((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pys_migrateÖs(    cCs‹|tjo|Snt|ƒ}|i}|tj oL|o||j}n ||j}| oti|||fƒ‚qƒn|SdS(N( sversionsNonesVerNums controlledscursupgrades directions exceptionss KnownErrorserr(s controlledsversionsupgradeserrscurs direction((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pys_migrate_versionís     !cKs)t|ƒ}t||ƒ}|iƒdS(sa%prog drop_version_control URL REPOSITORY_PATH Removes version control from a database. N(s create_enginesurlsenginesControlledSchemas repositorys controlledsdrop(surls repositorysoptssengines controlled((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pysdrop_version_controlýs cKst||SdS(s¨%prog manage FILENAME VARIABLES... Creates a script that runs Migrate with a set of default values. For example:: %prog manage manage.py --repository=/path/to/repository --url=sqlite:///project.db would create the script manage.py. The following two commands would then have exactly the same results:: python manage.py version %prog version --repository=/path/to/repository N(srepository_managesfilesopts(sfilesopts((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pysmanages(s__doc__smigrate.versioning.basesmigrate.versioning.repositorysmanagesrepository_managesmigrate.versioning.controlledsmigrate.versionings exceptionssscriptsscript_ssyssstatsinspects__all__sNoneshelpscreatescommitstestsversionssourcesversion_controls db_versionsupgrades downgrades_migrates_migrate_versionsdrop_version_control(s db_versionsdrop_version_controlshelpsmanages_migrate_versionsupgrades__all__sscriptscreatessourcesversionstests_migratesstatsinspectssyss downgradesversion_controlsrepository_manages exceptionsscommitsscript_((s:build/bdist.darwin-8.0.1-x86/egg/migrate/versioning/api.pys?s2      -  #        PK —ƒ5sp¨44migrate/versioning/logengine.py"""SQL statements are logged to a file, which may be run later with consistent results. This implies that this engine is write-only: SQL for all selects/reads will be output to a log, but you cannot manipulate their results, as the statements are not actually executed. Usage:: >>>from migrate.versioning import logengine >>># Create an engine with the log strategy >>>engine=create_engine('sqlite:///:memory:',strategy='logsql') >>> >>># Run some SQL to be logged. >>># This is write-only: you can't analyze the results! >>>select(['42'],engine=engine).execute() >>> >>># Save the log to a file >>>engine.write("filename.logsql") >>># Or save to a stream >>>from StringIO import StringIO >>>stream=StringIO() >>>engine.write(stream) >>> >>># Later, load and run the log with a regular engine >>>engine = create_engine('sqlite:///:memory:') >>>log = logengine.load("filename.logsql") >>>log.run(engine) """ import sys import pickle import traceback import sqlalchemy from sqlalchemy import engine,create_engine,text from sqlalchemy.engine import url,strategies,default,base from migrate.versioning import exceptions def load(*p,**k): return SqlLog.load(*p,**k) class LogDbapiCursor(object): """A fake DBAPI cursor""" description=None rowcount=None arraysize=None rownumber=None connection=None messages=None lastrowid=None def procname(self,procname,parameters=None): pass def close(self): pass def execute(self,operation,parameters=None): pass def execute(self,operation,seq_of_parameters): pass def fetchone(self): return None def fetchmany(self,size=None): return None def fetchall(self): return None def nextset(self): pass def setinputsizes(self,sizes): pass def setoutputsize(self,size,column): pass def scroll(self,value,mode=None): pass def next(self): pass def __iter__(self): pass class LogDbapiConnection(object): """A fake DBAPI connection We don't want a real connection to the database - we just need access to the dialect as if we had one. """ def close(self): pass def commit(self): pass def rollback(self): pass def cursor(self): return LogDbapiCursor() class SqlLogEntry(object): """A single entry in an SqlLog""" def __init__(self,statement,parameters=None): self.statement=statement self.parameters=parameters self.traceback=traceback.extract_stack() def trace(self): return ''.join(traceback.format_list(self.traceback)) def __eq__(self,value): return str(self)==str(value) def __str__(self): return '\n'.join(map(lambda x: str(x),(self.statement,self.parameters))) class SqlLog(object): """Logs SQL statements to be executed (with consistent behavior) later""" def __init__(self): self.entries=[] def add(self,statement,parameters=None): """Add a statement and its parameters to the log""" entry=SqlLogEntry(statement,parameters) self.entries.append(entry) def __len__(self): return len(self.entries) def write(self,file): """Write this SqlLog to a file""" fd=file if type(file) is str: fd=open(file,'w') pickle.dump(self,fd) if type(file) is str: fd.close() @classmethod def load(cls,file): """Load an SqlLog from a file, which may be analyzed or executed""" fd=file if type(file) is str: fd=open(file) self=pickle.load(fd) if type(file) is str: fd.close() return self @classmethod def create(cls,engine): """Create a new SqlLog, to which statements will be added""" self=cls() #TODO: we ought to verify correctness and such based on this engine return self def run(self,url_or_engine,conn_=None): """Run the contents of this SqlLog on a database""" engine=url_or_engine if type(url_or_engine) is str: engine=create_engine(url_or_engine) conn=conn_ if conn_ is None: conn=engine.contextual_connect() try: for entry in self.entries: try: conn._execute_raw(entry.statement,entry.parameters) except sqlalchemy.exceptions.SQLError,e: # SQL error: add the original traceback to the message raise exceptions.LogSqlError(e,entry) finally: if conn_ is None: # connection was made here - clean up conn.close() def __eq__(self,value): return str(self)==str(value) def __str__(self): return '\n'.join(map(lambda x: str(x),self.entries)) class LogConnection(engine.Connection): def _execute_raw(self,statement,parameters=None,cursor=None,echo=None,context=None,**kwargs): """Most engines execute SQL through here - this engine logs it""" cursor=None # No cursors in a stream connection; write only engine=self.engine if echo or engine.echo: engine.log(statement) engine.log(repr(parameters)) engine.logsql.add(statement,parameters) return cursor def close(self): """There should be no __connection to close""" if hasattr(self,'__connection'): self.__connection=None del self.__connection #def _begin_impl(self): # pass #def _commit_impl(self): # pass #def _rollback_impl(self): # pass class LogEngine(base.Engine): def __init__(self,*p,**k): if len(p)+len(k)>0: self.reset(*p,**k) def _make_url(self,url_): try: u = url.make_url(url_) except sqlalchemy.exceptions.ArgumentError: dbms = url_.split('://',1)[0] u = url.URL(dbms) return u def reset(self,name_or_url,**kwargs): # Pasted from sqlalchemy.engine.strategies.PlainEngineStrategy:create #u = url.make_url(name_or_url) u = self._make_url(name_or_url) module = u.get_module() args = u.query.copy() args.update(kwargs) dialect = module.dialect(**args) poolargs = {} for key in (('echo_pool', 'echo'), ('pool_size', 'pool_size'), ('max_overflow', 'max_overflow'), ('poolclass', 'poolclass'), ('pool_timeout','timeout'), ('pool', 'pool')): if kwargs.has_key(key[0]): poolargs[key[1]] = kwargs[key[0]] poolclass = getattr(module, 'poolclass', None) if poolclass is not None: poolargs.setdefault('poolclass', poolclass) poolargs['use_threadlocal'] = False provider = default.PoolConnectionProvider(dialect, u, **poolargs) #return LogEngine(provider, dialect, **args) #super(LogConnection,self).__init__(*p,**k) super(LogEngine,self).__init__(provider,dialect,**args) self.logsql=SqlLog.create(self) self.drivername = u.drivername def connect(self,**kwargs): return LogConnection(self,**kwargs) def contextual_connect(self,close_with_result=False,**kwargs): return self.connect(close_with_result=close_with_result,**kwargs) def write(self,*p,**k): """Write the sql log to a file""" return self.logsql.write(*p,**k) def raw_connection(self,*p,**k): return LogDbapiConnection() class LogEngineStrategy(strategies.EngineStrategy): def __init__(self): super(LogEngineStrategy,self).__init__('logsql') def create(self,name_or_url,**kwargs): # Content moved to engine.reset() ret = LogEngine() if name_or_url is not None: ret.reset(name_or_url,**kwargs) return ret LogEngineStrategy() PK —ƒ57;î`ffmigrate/versioning/cfgparse.pyfrom migrate.versioning.base import * from migrate.versioning import pathed from ConfigParser import ConfigParser #__all__=['MigrateConfigParser'] class Parser(ConfigParser): """A project configuration file""" def to_dict(self,sections=None): """It's easier to access config values like dictionaries""" return self._sections class Config(pathed.Pathed,Parser): def __init__(self,path,*p,**k): """Confirm the config file exists; read it""" self.require_found(path) pathed.Pathed.__init__(self,path) Parser.__init__(self,*p,**k) self.read(path) PKVN58/Ç!migrate/versioning/script/sql.pyc;ò &dsEc@s!dkTdefd„ƒYZdS((s*sSqlFilecBs tZdZd„Zd„ZRS(s'A file containing plain SQL statements.cCs?tt|ƒi|ƒt|ƒ}|iƒ|_|i ƒdS(N( ssupersSqlFilesselfs__init__spathsopensfilesreadstextsclose(sselfspathsfile((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/script/sql.pys__init__s cCsi|i}|iƒ}zB|iƒ}y|i|ƒ|iƒWn|i ƒ‚nXWd|i ƒXdS(N( sselfstextsenginesconnectsconnsbeginstranssexecutescommitsrollbacksclose(sselfsenginesstepstextstranssconn((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/script/sql.pysrun s      (s__name__s __module__s__doc__s__init__srun(((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/script/sql.pysSqlFiles  N(sscripts ScriptFilesSqlFile(sSqlFile((sAbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/script/sql.pys?sPK —ƒ5†ð€œ• • migrate/versioning/script/py.pyfrom script import * from logsql import LogsqlFile from migrate.versioning.template import template from migrate.versioning import exceptions import sqlalchemy import migrate.run class PythonFile(ScriptFile): def __init__(self,path): super(PythonFile,self).__init__(path) #self.module=import_path(path) def _get_module(self): if not hasattr(self,'_module'): self._module = self.verify_module(self.path) return self._module module = property(_get_module) def _get_logsql(self): try: return self.module.logsql except AttributeError: return False logsql = property(_get_logsql) @classmethod def create(cls,path,**opts): """Create an empty migration script""" cls.require_notfound(path) filename = None if opts.get('logsql',False): filename = 'logsql.py_tmpl' src=template.get_script(filename) shutil.copy(src,path) @classmethod def verify(cls,path): # Verifying valid python script is done when .module is referenced super(PythonFile,cls).verify(path) @classmethod @logsql_engine def verify_module(cls,path): """Ensure this is a valid script, or raise InvalidScriptError""" # Try to import and get the upgrade() func try: module=import_path(path) except: # If the script itself has errors, that's not our problem raise try: assert callable(module.upgrade) except Exception,e: raise exceptions.InvalidScriptError(path+': %s'%str(e)) return module def _func(self,funcname): try: return getattr(self.module,funcname) except AttributeError: msg = "The function %s is not defined in this script" raise exceptions.ScriptError(msg%funcname) @logsql_engine def compile(self,database,operation,path=None): """Compile a Python script into a logfile or log object""" # Change the engine referenced by all migration scripts try: self.module.migrate_engine.reset(database) #migrate.run.migrate_engine.reset(database) except (ImportError,sqlalchemy.exceptions.InvalidRequestError, AttributeError,#sqlite ): raise exceptions.ScriptError("The database %s doesn't exist"%database) # Run the migration function. Must exist if script/op are valid try: funcname = operations[operation] except KeyError: raise exceptions.ScriptError("%s is not a valid migration function"%operation) func = self._func(funcname) func() # Success - return the log, or a file containing the log if path given ret = self.module.migrate_engine.logsql #ret = migrate.run.migrate_engine.logsql if path is not None: ret = LogsqlFile.create(ret,path) return ret def run(self,engine,step): if step > 0: op = 'upgrade' elif step < 0: op = 'downgrade' else: raise exceptions.ScriptError("%d is not a valid step"%step) funcname = operations[op] migrate.run.migrate_engine = engine #self.module.migrate_engine = engine func = self._func(funcname) func() migrate.run.migrate_engine = None PK —ƒ5»™äNN%migrate/versioning/script/__init__.pyfrom py import * from logsql import * from sql import * from script import * PK —ƒ5ˆ¥ migrate/versioning/script/sql.pyfrom script import * class SqlFile(ScriptFile): """A file containing plain SQL statements.""" def __init__(self,path): super(SqlFile,self).__init__(path) file = open(path) self.text = file.read() file.close() def run(self,engine,step): text = self.text # Don't rely on SA's autocommit here # (SA uses .startswith to check if a commit is needed. What if script # starts with a comment?) conn = engine.connect() try: trans = conn.begin() try: conn.execute(text) # Success trans.commit() except: trans.rollback() raise finally: conn.close() PK —ƒ5ò˜Õ¯ ¯ #migrate/versioning/script/script.pyfrom migrate.versioning.base import * from migrate.versioning.pathed import * from migrate.versioning import exceptions import os import sys import sqlalchemy import migrate.run def import_path(fullpath): """ Import a file with full path specification. Allows one to import from anywhere, something __import__ does not do. """ # http://zephyrfalcon.org/weblog/arch_d7_2002_08_31.html path, filename = os.path.split(fullpath) filename, ext = os.path.splitext(filename) sys.path.append(path) module = __import__(filename) reload(module) # Might be out of date during tests del sys.path[-1] return module def logsql_engine(func,force=False): """migrate.run.migrate_engine is a logengine in the decorated function""" def entangle(*p,**k): if force or (not getattr(migrate.run,'migrate_engine',None)): migrate.run.migrate_engine = sqlalchemy.create_engine(None,strategy='logsql') reload(migrate) try: return func(*p,**k) finally: try: del migrate.run.migrate_engine except AttributeError: # If this disappeared on its own, that's ok pass return entangle class ScriptFile(Pathed): """Base class for other types of scripts All scripts have the following properties: source (script.source()) The source code of the script version (script.version()) The version number of the script operations (script.operations()) The operations defined by the script: upgrade(), downgrade() or both. Returns a tuple of operations. Can also check for an operation with ex. script.operation(Script.ops.up) """ logsql = None """If true, this file should be compiled upon commit""" def __init__(self,path): log.info('Loading script %s...'%path) self.verify(path) super(ScriptFile,self).__init__(path) log.info('Script %s loaded successfully'%path) @classmethod def verify(cls,path): """Ensure this is a valid script, or raise InvalidScriptError Child classes might add to this by extending _verify """ try: cls.require_found(path) except: raise exceptions.InvalidScriptError(path) def version(self): raise NotImplementedError() #TODO def source(self): fd=open(self.path) ret=fd.read() fd.close() return ret def operations(self): # Must be defined in child class raise NotImplementedError() def operation(self,op): return op in self.operations() def run(self,engine): raise NotImplementedError() PKVN58™É-èè&migrate/versioning/script/__init__.pyc;ò &dsEc@s dkTdkTdkTdkTdS((s*N(spyslogsqlssqlsscript(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/versioning/script/__init__.pys?sPK —ƒ5pÂ`)#migrate/versioning/script/logsql.pyfrom script import * from migrate.versioning import logengine import migrate.run class LogsqlFile(ScriptFile): """A file containing a log of SQLAlchemy statements""" # logengine.SqlLog covers most things here; this is a wrapper def __init__(self,path): super(LogsqlFile,self).__init__(path) self.log = logengine.SqlLog.load(path) @classmethod def create(cls,log,path): """Save a given log to a file""" cls.require_notfound(path) log.write(path) ret = cls(path) return ret @logsql_engine def run(self,engine,step): return self.log.run(engine) PK —ƒ5ø½ævff#migrate/versioning/base/__init__.py"""Things that should be imported by all migrate packages""" from logger import * from const import * PKWN58ùžJ¬¬!migrate/versioning/base/const.pyc;ò &dsEc@sCdklZdddddfZeƒZded|i|ƒ|idƒ|i|i|ƒƒ|iƒdS(NsDROP CONSTRAINT (sselfsstart_alter_tables constraintsappendsget_constraint_namesexecute(sselfs constraint((s=build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/ansisql.pys_visit_constraintôs  cOs|i||ŽSdS(N(sselfs_visit_constraintspsk(sselfspsk((s=build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/ansisql.pys$visit_migrate_primary_key_constraintúscOs|i||ŽSdS(N(sselfs_visit_constraintspsk(sselfspsk((s=build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/ansisql.pys$visit_migrate_foreign_key_constraintýs(s__name__s __module__s_visit_constraints$visit_migrate_primary_key_constraints$visit_migrate_foreign_key_constraint(((s=build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/ansisql.pysANSIConstraintDropperós  sANSIDialectChangesetcBs#tZeZeZeZd„ZRS(NcCs tƒ‚dS(N(sNotImplementedError(sselfs connections table_name((s=build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/ansisql.pysreflectconstraintss( s__name__s __module__sANSIColumnGeneratorscolumngeneratorsANSIColumnDroppers columndroppersANSISchemaChangers schemachangersreflectconstraints(((s=build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/ansisql.pysANSIDialectChangesetscCsCtiitf7_tiitf7_tiitf7_dS(N(sansisqls ANSIDialects __bases__sANSIDialectChangesetsANSISchemaGeneratorsANSIConstraintGeneratorsANSISchemaDroppersANSIConstraintDropper(((s=build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/ansisql.pys_patchsN(s__doc__s sqlalchemysansisqlsmigrate.changesets constraintsutils exceptionssobjectsRawAlterTableVisitorsenginesSchemaIteratorsAlterTableVisitorsANSISchemaGeneratorsANSIColumnGeneratorsANSIColumnDroppersANSISchemaChangersANSIConstraintCommonsANSIConstraintGeneratorsANSIConstraintDroppersANSIDialectChangesets_patch(sRawAlterTableVisitors constraintsANSIColumnDroppersANSIColumnGeneratorsutilsAlterTableVisitorsansisqlsANSIConstraintDroppers exceptionssANSIConstraintGeneratorsANSISchemaChangers_patchsANSIConstraintCommonsANSIDialectChangeset((s=build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/ansisql.pys?s + q ! PK —ƒ5ˆâu-5-5migrate/changeset/__init__.pyimport re import sqlalchemy from databases import * import ansisql from constraint import * def create_column(column,table=None,*p,**k): if table is not None: return table.create_column(column,*p,**k) return column.create(*p,**k) def drop_column(column,table=None,*p,**k): if table is not None: return table.drop_column(column,*p,**k) return column.drop(*p,**k) def _to_table(table,engine=None): if isinstance(table,sqlalchemy.Table): return table # Given: table name, maybe an engine meta = sqlalchemy.DynamicMetaData() if engine is not None: meta.connect(engine) return sqlalchemy.Table(table,meta) def _to_index(index,table=None,engine=None): if isinstance(index,sqlalchemy.Index): return index # Given: index name; table name required table = _to_table(table,engine) ret = sqlalchemy.Index(index) ret.table = table return ret def rename_table(table,name,engine=None): """Rename a table, given the table's current name and the new name.""" table = _to_table(table,engine) table.rename(name) def rename_index(index,name,table=None,engine=None): """Rename an index Takes an index name/object, a table name/object, and an engine. Engine and table aren't required if an index object is given. """ index = _to_index(index,table,engine) index.rename(name) def _engine_run_visitor(engine,visitorcallable,element,**kwargs): conn = engine.connect() try: element.accept_schema_visitor(visitorcallable(engine,conn.proxy,connection=conn)) finally: conn.close() def alter_column(*p,**k): """Alter a column Parameters: column name, table name, an engine, and the properties of that column to change """ if len(p) and isinstance(p[0],sqlalchemy.Column): col = p[0] else: col = None if 'table' not in k: k['table'] = col.table if 'engine' not in k: k['engine'] = k['table'].engine engine = k['engine'] delta = _ColumnDelta(*p,**k) visitorcallable = engine.dialect.schemachanger #engine._run_visitor(visitorcallable,delta) _engine_run_visitor(engine,visitorcallable,delta) # Update column if col is not None: # Special case: change column key on rename, if key not explicit # Used by SA : table.c.[key] # # This fails if the key was explit AND equal to the column name. # (It changes the key name when it shouldn't.) # Not much we can do about it. if 'name' in delta.keys(): if (col.name == col.key): newname = delta['name'] del col.table.c[col.key] setattr(col,'key',newname) col.table.c[col.key] = col # Change all other attrs for key,val in delta.iteritems(): setattr(col,key,val) def _normalize_table(column,table): if table is not None: if table is not column.table: # This is a bit of a hack: we end up with dupe PK columns here pk_names = map(lambda c: c.name, table.primary_key) if column.primary_key and pk_names.count(column.name): index = pk_names.index(column_name) del table.primary_key[index] table.append_column(column) return column.table class _WrapRename(object): def __init__(self,item,name): self.item = item self.name = name 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.Index): suffix = 'index' funcname = 'visit_%s'%suffix func = getattr(visitor,funcname) param = self.item,self.name return func(param) class _ColumnDelta(dict): """Extracts the differences between two columns/column-parameters""" def __init__(self,*p,**k): """Extract ALTER-able differences from two columns May receive parameters arranged in several different ways: * old_column_object,new_column_object,*parameters Identifies attributes that differ between the two columns. Parameters specified outside of either column are always executed and override column differences. * column_object,[current_name,]*parameters Parameters specified are changed; table name is extracted from column object. Name is changed to column_object.name from current_name, if current_name is specified. If not specified, name is unchanged. * current_name,table,*parameters 'table' may be either an object or a name """ # Things are initialized differently depending on how many column # parameters are given. Figure out how many and call the appropriate # method. if len(p) >= 1 and isinstance(p[0],sqlalchemy.Column): # At least one column specified if len(p) >= 2 and isinstance(p[1],sqlalchemy.Column): # Two columns specified func = self._init_2col else: # Exactly one column specified func = self._init_1col else: # Zero columns specified func = self._init_0col diffs = func(*p,**k) self._set_diffs(diffs) # Column attributes that can be altered diff_keys = ('name','type','nullable','default','primary_key','foreign_key') def _get_table_name(self): if isinstance(self._table,basestring): ret = self._table else: ret = self._table.name return ret table_name = property(_get_table_name) def _get_table(self): if isinstance(self._table,basestring): ret = None else: ret = self._table return ret table = property(_get_table) def _init_0col(self,current_name,*p,**k): p,k = self._init_normalize_params(p,k) table = k.pop('table') self.current_name = current_name self._table = table return k def _init_1col(self,col,*p,**k): p,k = self._init_normalize_params(p,k) self._table = k.pop('table',None) or col.table self.result_column = col.copy() if 'current_name' in k: # Renamed self.current_name = k.pop('current_name') k.setdefault('name',col.name) else: self.current_name = col.name return k def _init_2col(self,start_col,end_col,*p,**k): p,k = self._init_normalize_params(p,k) self.result_column = start_col.copy() self._table = k.pop('table',None) or start_col.table or end_col.table self.current_name = start_col.name for key in ('name','nullable','default','primary_key','foreign_key'): val = getattr(end_col,key,None) if getattr(start_col,key,None) != val: k.setdefault(key,val) if not self.column_types_eq(start_col.type,end_col.type): k.setdefault('type',end_col.type) return k def _init_normalize_params(self,p,k): p = list(p) if len(p): k.setdefault('name',p.pop(0)) if len(p): k.setdefault('type',p.pop(0)) # TODO: sequences? FKs? return p,k def _set_diffs(self,diffs): for key in self.diff_keys: if key in diffs: self[key] = diffs[key] if getattr(self,'result_column',None) is not None: setattr(self.result_column,key,diffs[key]) def column_types_eq(self,this,that): ret = isinstance(this,that.__class__) ret = ret or isinstance(that,this.__class__) # String length is a special case if ret and isinstance(that,sqlalchemy.types.String): ret = (getattr(this,'length',None) == getattr(that,'length',None)) return ret def accept_schema_visitor(self,visitor): return visitor.visit_column(self) class ChangesetTable(object): """Changeset extensions to SQLAlchemy tables.""" def create_column(self,column): """Creates a column The column parameter may be a column definition or the name of a column in this table. """ if not isinstance(column,sqlalchemy.Column): # It's a column name column = getattr(self.c,str(column)) column.create(table=self) def drop_column(self,column): """Drop a column, given its name or definition.""" if not isinstance(column,sqlalchemy.Column): # It's a column name try: column = getattr(self.c,str(column),None) except AttributeError: # That column isn't part of the table. We don't need its entire # definition to drop the column, just its name, so create a dummy # column with the same name. column = sqlalchemy.Column(str(column)) column.drop(table=self) def _meta_key(self): return schema._get_table_key(self.name,self.schema) def deregister(self): """Remove this table from its metadata""" key = self._meta_key() meta = self.metadata if key in meta.tables: del meta.tables[key] def rename(self,name,*args,**kwargs): """Rename this table This changes both the database name and the name of this Python object """ engine = self.engine visitorcallable = engine.dialect.schemachanger param = _WrapRename(self,name) #engine._run_visitor(visitorcallable,param,*args,**kwargs) _engine_run_visitor(engine,visitorcallable,param,*args,**kwargs) # Fix metadata registration meta = self.metadata self.deregister() self.name = name self._set_parent(meta) def _get_fullname(self): """Fullname should always be up to date""" # Copied from Table constructor if self.schema is not None: ret = "%s.%s"%(self.schema,self.name) else: ret = self.name return ret fullname = property(_get_fullname,(lambda self,val: None)) class ChangesetColumn(object): """Changeset extensions to SQLAlchemy columns""" def alter(self,*p,**k): """Alter a column's definition: ALTER TABLE ALTER COLUMN May supply a new column object, or a list of properties to change. For example; the following are equivalent: col.alter(Column('myint',Integer,nullable=False)) col.alter('myint',Integer,nullable=False) col.alter(name='myint',type=Integer,nullable=False) Column name, type, default, and nullable may be changed here. Note that for column defaults, only PassiveDefaults are managed by the database - changing others doesn't make sense. """ return alter_column(self,*p,**k) def create(self,table=None,*args,**kwargs): """Create this column in the database. Assumes the given table exists. ALTER TABLE ADD COLUMN, for most databases. """ table = _normalize_table(self,table) engine = table.engine visitorcallable = engine.dialect.columngenerator engine._run_visitor(visitorcallable,self,*args,**kwargs) return self def drop(self,table=None,*args,**kwargs): """Drop this column from the database, leaving its table intact. ALTER TABLE DROP COLUMN, for most databases. """ table = _normalize_table(self,table) engine = table.engine visitorcallable = engine.dialect.columndropper engine._run_visitor(visitorcallable,self,*args,**kwargs) ## Remove col from table object, too #del table._columns[self.key] #if self in table.primary_key: # table.primary_key.remove(self) return self class ChangesetIndex(object): """Changeset extensions to SQLAlchemy Indexes""" def rename(self,name,*args,**kwargs): """Change the name of an index. This changes both the Python object name and the database name. """ engine = self.table.engine visitorcallable = engine.dialect.schemachanger param = _WrapRename(self,name) #engine._run_visitor(visitorcallable,param,*args,**kwargs) _engine_run_visitor(engine,visitorcallable,param,*args,**kwargs) self.name = name def _autocommit_hack(self, statement): """when no Transaction is present, this is called after executions to provide "autocommit" behavior. This adds autocommit after ALTER TABLE statements as well """ #pat = r'UPDATE|INSERT|CREATE|DELETE|DROP' pat = r'UPDATE|INSERT|CREATE|DELETE|DROP|ALTER' if not self.in_transaction() and re.match(pat,statement.lstrip().upper()): self._commit_impl() def _patch(): """All the 'ugly' operations that patch SQLAlchemy's internals.""" sqlalchemy.engine.base.Connection._autocommit = _autocommit_hack sqlalchemy.schema.Table.__bases__ += (ChangesetTable,) sqlalchemy.schema.Column.__bases__ += (ChangesetColumn,) sqlalchemy.schema.Index.__bases__ += (ChangesetIndex,) import databases ansisql._patch() constraint._patch() for db in databases.__all__: getattr(databases,db)._patch() _patch() PKZN58ƒ“Çnn migrate/changeset/constraint.pyc;ò &dsEc@sqdkZdklZdefd„ƒYZdeeifd„ƒYZdeeifd„ƒYZd„ZdS( N(sschemasConstraintChangesetcBsPtZed„Zed„Zed„Zd„Zd„Zd„Z d„Z RS(NcCs«g}t}xŽ|D]†}t|tiƒo`|itj o |tjo |i}n|o"di |ii |i fƒ}qŒ|i }n|i |ƒqW||fSdS(sDGiven: column objects or names; return col names and (maybe) a tables.N( scolnamessNonestablescolsscols isinstancesschemasColumnsfullnamesjoinsnamesappend(sselfscolssfullnamescolstablescolnames((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys_normalize_columnss " cCs+|tjo |i}n|i|ƒdS(N(senginesNonesselfscreate(sselfsengine((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pyscreates  cCs+|tjo |i}n|i|ƒdS(N(senginesNonesselfsdrop(sselfsengine((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysdrops  cCs|iiƒSdS(N(sselfstables_derived_metadata(sself((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys_derived_metadatascOs tƒ‚dS(N(sNotImplementedError(sselfsvisitorspsk((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysaccept_schema_visitorscOs;yt||ƒ}Wntj o dSnX||ƒSdS(s6Call the visitor only if it defines the given functionN(sgetattrsvisitorsfuncsAttributeErrorsself(sselfsvisitorsfuncspsk((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys_accept_schema_visitor!s  cCs tƒ‚dS(N(sNotImplementedError(sself((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysautoname(s( s__name__s __module__sFalses_normalize_columnssNonescreatesdrops_derived_metadatasaccept_schema_visitors_accept_schema_visitorsautoname(((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysConstraintChangesets      sPrimaryKeyConstraintcBs5tZd„Zd„Zd„Zd„Zd„ZRS(NcOsb|i|ƒ\}}|id|ƒ}tt|ƒi ||Ž|t j o|i |ƒndS(Nstable( sselfs_normalize_columnsscolsscolnamesstableskwargsspopssupersPrimaryKeyConstraints__init__sNones _set_parent(sselfscolsskwargsstablescolnames((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys__init__,s  cCs#||_tt|ƒi|ƒSdS(N(stablesselfssupersConstraintChangesets _set_parent(sselfstable((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys _set_parent3s cCs!dtd|iiƒ}|SdS(s/Mimic the database's automatic constraint namess%(table)s_pkeystableN(sdictsselfstablesnamesret(sselfsret((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysautoname6scOs0tt|ƒi||Ž}|iiƒ|SdS(N( ssupersPrimaryKeyConstraintsselfsdropsargsskwargssretscolumnssclear(sselfsargsskwargssret((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysdrop<s cOs d}|i||||ŽSdS(Ns$visit_migrate_primary_key_constraint(sfuncsselfs_accept_schema_visitorsvisitorspsk(sselfsvisitorspsksfunc((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysaccept_schema_visitorAs(s__name__s __module__s__init__s _set_parentsautonamesdropsaccept_schema_visitor(((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysPrimaryKeyConstraint+s     sForeignKeyConstraintcBsMtZd„Zd„ZeeƒZd„ZeeƒZd„Zd„Z RS(Nc Osƒ|i|ƒ\}}|id|ƒ}|i|dtƒ\}}t t |ƒi ||||Ž|tj o|i|ƒndS(Nstablesfullname(sselfs_normalize_columnsscolumnsscolnamesstableskspops refcolumnssTrues refcolnamessreftablessupersForeignKeyConstraints__init__spsNones _set_parent( sselfscolumnss refcolumnsspsksreftables refcolnamesstablescolnames((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys__init__Gs  cCs/gi}|iD]}||iƒq~SdS(N(sappends_[1]sselfselementssescolumn(sselfs_[1]se((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys_get_referencedOscCs|idiSdS(Ni(sselfs referencedstable(sself((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys _get_reftableSscCs-dtd|iid|iiƒ}|SdS(s/Mimic the database's automatic constraint namess%(table)s_%(reftable)s_fkeystablesreftableN(sdictsselfstablesnamesreftablesret(sselfsret((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysautonameWscOs d}|i||||ŽSdS(Ns$visit_migrate_foreign_key_constraint(sfuncsselfs_accept_schema_visitorsvisitorspsk(sselfsvisitorspsksfunc((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysaccept_schema_visitor_s( s__name__s __module__s__init__s_get_referencedspropertys referenceds _get_reftablesreftablesautonamesaccept_schema_visitor(((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pysForeignKeyConstraintFs      cCsdS(N((((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys_patchcs(s sqlalchemysschemasobjectsConstraintChangesetsPrimaryKeyConstraintsForeignKeyConstraints_patch(s sqlalchemysConstraintChangesetsForeignKeyConstraintsPrimaryKeyConstraints_patchsschema((s@build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/constraint.pys?s  'PK —ƒ5ëúa+aamigrate/changeset/util.py def prepend_base(cls,base): cls.__bases__ = (base,)+cls.__bases__ return cls.__bases__ PK —ƒ5î9\O(O(migrate/changeset/ansisql.py"""Extensions to SQLAlchemy for altering existing tables. At the moment, this isn't so much based off of ANSI as much as things that just happen to work with multiple databases. """ from sqlalchemy import * from sqlalchemy import ansisql from migrate.changeset import constraint,util,exceptions class RawAlterTableVisitor(object): """Common operations for 'alter table' statements""" def _to_table(self,param): if isinstance(param,(Column,Index,schema.Constraint)): ret = param.table else: ret = param return ret def _to_table_name(self,param): ret = self._to_table(param) if isinstance(ret,Table): ret = ret.fullname return ret def start_alter_table(self,param): table = self._to_table(param) table_name = self._to_table_name(table) self.append("\nALTER TABLE %s "%table_name) return table def _pk_constraint(self,table,column,status): """Create a primary key constraint from a table, column Status: true if the constraint is being added; false if being dropped """ if isinstance(column,basestring): column = getattr(table.c,name) ret = constraint.PrimaryKeyConstraint(*table.primary_key) if status: # Created PK ret.c.append(column) else: # Dropped PK #cons.remove(col) names = [c.name for c in cons.c] index = names.index(col.name) del ret.c[index] # Allow explicit PK name assignment if isinstance(pk,basestring): ret.name = pk return ret class AlterTableVisitor(engine.SchemaIterator,RawAlterTableVisitor): """Common operations for 'alter table' statements""" class ANSIColumnGenerator(AlterTableVisitor,ansisql.ANSISchemaGenerator): """Extends ansisql generator for column creation (alter table add col)""" def visit_column(self,column): """Create a column (table already exists); #32""" table = self.start_alter_table(column) self.append(" ADD ") pks = table.primary_key colspec = self.get_column_specification(column) self.append(colspec) self.execute() #if column.primary_key: # cons = self._pk_constraint(table,column,True) # cons.drop() # cons.create() def visit_table(self,table): pass class ANSIColumnDropper(AlterTableVisitor): """Extends ansisql dropper for column dropping (alter table drop col)""" def visit_column(self,column): """Drop a column; #33""" table = self.start_alter_table(column) self.append(" DROP COLUMN %s"%column.name) self.execute() #if column.primary_key: # cons = self._pk_constraint(table,column,False) # cons.create() class ANSISchemaChanger(AlterTableVisitor,ansisql.ANSISchemaGenerator): """Manages changes to existing schema elements. Note that columns are schema elements; "alter table add column" is in SchemaGenerator. All items may be renamed. Columns can also have many of their properties - type, for example - changed. Each function is passed a tuple, containing (object,name); where object is a type of object you'd expect for that function (ie. table for visit_table) and name is the object's new name. NONE means the name is unchanged. """ def visit_table(self,param): """Rename a table; #38. Other ops aren't supported.""" table,newname = param self.start_alter_table(table) self.append("RENAME TO %s"%newname) self.execute() def visit_column(self,delta): """Rename/change a column; #34/#35""" # ALTER COLUMN is implemented as several ALTER statements keys = delta.keys() if 'type' in keys: self._run_subvisit(delta,self._visit_column_type) if 'nullable' in keys: self._run_subvisit(delta,self._visit_column_nullable) if 'default' in keys: self._run_subvisit(delta,self._visit_column_default) #if 'primary_key' in keys: # #self._run_subvisit(delta,self._visit_column_primary_key) # self._visit_column_primary_key(delta) #if 'foreign_key' in keys: # self._visit_column_foreign_key(delta) if 'name' in keys: self._run_subvisit(delta,self._visit_column_name) def _run_subvisit(self,delta,func,col_name=None,table_name=None): if table_name is None: table_name = delta.table_name if col_name is None: col_name = delta.current_name ret = func(table_name,col_name,delta) self.execute() return ret def _visit_column_foreign_key(self,delta): table = delta.table column = getattr(table.c,delta.current_name) cons = constraint.ForeignKeyConstraint(column,autoload=True) fk = delta['foreign_key'] if fk: # For now, cons.columns is limited to one column: # no multicolumn FKs column.foreign_key = ForeignKey(*cons.columns) else: column_foreign_key = None cons.drop() cons.create() def _visit_column_primary_key(self,delta): table = delta.table col = getattr(table.c,delta.current_name) pk = delta['primary_key'] cons = self._pk_constraint(table,col,pk) cons.drop() cons.create() def _visit_column_nullable(self,table_name,col_name,delta): nullable = delta['nullable'] table = self._to_table(delta) self.start_alter_table(table_name) self.append("ALTER COLUMN %s "%col_name) if nullable: self.append("DROP NOT NULL") else: self.append("SET NOT NULL") def _visit_column_default(self,table_name,col_name,delta): default = delta['default'] # Default must be a PassiveDefault; else, ignore # (Non-PassiveDefaults are managed by the app, not the db) if default is not None: if not isinstance(default,PassiveDefault): return # Dummy column: get_col_default_string needs a column for some reason dummy = Column(None,None,default=default) default_text = self.get_column_default_string(dummy) self.start_alter_table(table_name) self.append("ALTER COLUMN %s "%col_name) if default_text is not None: self.append("SET DEFAULT %s"%default_text) else: self.append("DROP DEFAULT") def _visit_column_type(self,table_name,col_name,delta): type = delta['type'] if not isinstance(type,types.AbstractType): # It's the class itself, not an instance... make an instance type = type() type_text = type.engine_impl(self.engine).get_col_spec() self.start_alter_table(table_name) self.append("ALTER COLUMN %s TYPE %s"%(col_name,type_text)) def _visit_column_name(self,table_name,col_name,delta): new_name = delta['name'] self.start_alter_table(table_name) self.append("RENAME COLUMN %s TO %s"%(col_name,new_name)) def visit_index(self,param): """Rename an index; #36""" index,newname = param #self.start_alter_table(index) #self.append("RENAME INDEX %s TO %s"%(index.name,newname)) self.append("ALTER INDEX %s RENAME TO %s"%(index.name,newname)) self.execute() class ANSIConstraintCommon(RawAlterTableVisitor): """ Migrate's constraints require a separate creation function from SA's: Migrate's constraints are created independently of a table; SA's are created at the same time as the table. """ def get_constraint_name(self,cons): if cons.name is not None: ret = cons.name else: ret = cons.name = cons.autoname() return ret class ANSIConstraintGenerator(ANSIConstraintCommon): def get_constraint_specification(self,cons,**kwargs): if isinstance(cons,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): params = dict( columns=','.join([c.name for c in cons.columns]), reftable=cons.reftable, referenced=','.join([c.name for c in cons.referenced]), name=self.get_constraint_name(cons), ) ret = "CONSTRAINT %(name)s FOREIGN KEY (%(columns)s) "\ "REFERENCES %(reftable)s (%(referenced)s)"%params else: raise exceptions.InvalidConstraintError(cons) return ret def _visit_constraint(self,constraint): table = self.start_alter_table(constraint) self.append("ADD ") spec = self.get_constraint_specification(constraint) self.append(spec) self.execute() def visit_migrate_primary_key_constraint(self,*p,**k): return self._visit_constraint(*p,**k) def visit_migrate_foreign_key_constraint(self,*p,**k): return self._visit_constraint(*p,**k) class ANSIConstraintDropper(ANSIConstraintCommon): def _visit_constraint(self,constraint): self.start_alter_table(constraint) self.append("DROP CONSTRAINT ") self.append(self.get_constraint_name(constraint)) self.execute() def visit_migrate_primary_key_constraint(self,*p,**k): return self._visit_constraint(*p,**k) def visit_migrate_foreign_key_constraint(self,*p,**k): return self._visit_constraint(*p,**k) class ANSIDialectChangeset(object): columngenerator = ANSIColumnGenerator columndropper = ANSIColumnDropper schemachanger = ANSISchemaChanger def reflectconstraints(self,connection,table_name): raise NotImplementedError() def _patch(): ansisql.ANSIDialect.__bases__ += (ANSIDialectChangeset,) ansisql.ANSISchemaGenerator.__bases__ += (ANSIConstraintGenerator,) ansisql.ANSISchemaDropper.__bases__ += (ANSIConstraintDropper,) PK —ƒ5¼šÀæ}}migrate/changeset/exceptions.py class Error(Exception): pass class NotSupportedError(Error): pass class InvalidConstraintError(Error): pass PKXN58àòʶmigrate/changeset/util.pyc;ò &dsEc@s d„ZdS(cCs|f|i|_|iSdS(N(sbasesclss __bases__(sclssbase((s:build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/util.pys prepend_basesN(s prepend_base(s prepend_base((s:build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/util.pys?sPKXN58vü YLLmigrate/changeset/__init__.pyc;ò &dsEc@sdkZdkZdkTdkZdkTed„Zed„Zed„Zeed„Z ed„Z eed„Z d„Z d „Z d „Zd efd „ƒYZd efd„ƒYZdefd„ƒYZdefd„ƒYZdefd„ƒYZd„Zd„ZeƒdS(N(s*cOs8|tj o|i|||ŽSn|i||ŽSdS(N(stablesNones create_columnscolumnspskscreate(scolumnstablespsk((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys create_columns cOs8|tj o|i|||ŽSn|i||ŽSdS(N(stablesNones drop_columnscolumnspsksdrop(scolumnstablespsk((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys drop_column s cCsYt|tiƒo|Sntiƒ}|tj o|i|ƒnti||ƒSdS(N( s isinstancestables sqlalchemysTablesDynamicMetaDatasmetasenginesNonesconnect(stablesenginesmeta((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _to_tables   cCsJt|tiƒo|Snt||ƒ}ti|ƒ}||_|SdS(N(s isinstancesindexs sqlalchemysIndexs _to_tablestablesenginesret(sindexstablesenginesret((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _to_indexs  cCs t||ƒ}|i|ƒdS(s@Rename a table, given the table's current name and the new name.N(s _to_tablestablesenginesrenamesname(stablesnamesengine((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys rename_table#scCs#t|||ƒ}|i|ƒdS(sšRename an index Takes an index name/object, a table name/object, and an engine. Engine and table aren't required if an index object is given. N(s _to_indexsindexstablesenginesrenamesname(sindexsnamestablesengine((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys rename_index(scKsA|iƒ}z#|i|||id|ƒƒWd|iƒXdS(Ns connection(senginesconnectsconnselementsaccept_schema_visitorsvisitorcallablesproxysclose(senginesvisitorcallableselementskwargssconn((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys_engine_run_visitor0s  #c OsZt|ƒot|dtiƒo|d}nt}d|jo|i|dbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys alter_column7s,$       cCsŒ|tj ot||ij o`td„|iƒ}|io|i|iƒo|it ƒ}|i|=n|i |ƒqn|iSdS(NcCs|iS(N(scsname(sc((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys`s( stablesNonescolumnsmaps primary_keyspk_namesscountsnamesindexs column_names append_column(scolumnstablesindexspk_names((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys_normalize_table\s s _WrapRenamecBstZd„Zd„ZRS(NcCs||_||_dS(N(sitemsselfsname(sselfsitemsname((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys__init__is cCsyt|itiƒo d}n!t|itiƒo d}nd|}t||ƒ}|i|i f}||ƒSdS(Nstablesindexsvisit_%s( s isinstancesselfsitems sqlalchemysTablessuffixsIndexsfuncnamesgetattrsvisitorsfuncsnamesparam(sselfsvisitorssuffixsparamsfuncnamesfunc((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pysaccept_schema_visitorms   (s__name__s __module__s__init__saccept_schema_visitor(((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _WrapRenamehs s _ColumnDeltacBs˜tZdZd„ZddddddfZd„ZeeƒZd „ZeeƒZ d „Z d „Z d „Z d „Z d„Zd„Zd„ZRS(s>Extracts the differences between two columns/column-parameterscOs—t|ƒdjot|dtiƒoDt|ƒdjot|dtiƒo |i}qw|i}n |i }|||Ž}|i |ƒdS(sExtract ALTER-able differences from two columns May receive parameters arranged in several different ways: * old_column_object,new_column_object,*parameters Identifies attributes that differ between the two columns. Parameters specified outside of either column are always executed and override column differences. * column_object,[current_name,]*parameters Parameters specified are changed; table name is extracted from column object. Name is changed to column_object.name from current_name, if current_name is specified. If not specified, name is unchanged. * current_name,table,*parameters 'table' may be either an object or a name iiiN( slensps isinstances sqlalchemysColumnsselfs _init_2colsfuncs _init_1cols _init_0colsksdiffss _set_diffs(sselfspsksdiffssfunc((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys__init__{s**   snamestypesnullablesdefaults primary_keys foreign_keycCs4t|itƒo |i}n |ii}|SdS(N(s isinstancesselfs_tables basestringsretsname(sselfsret((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys_get_table_names  cCs.t|itƒo t}n |i}|SdS(N(s isinstancesselfs_tables basestringsNonesret(sselfsret((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _get_table¥s  cOsA|i||ƒ\}}|idƒ}||_||_|SdS(Nstable(sselfs_init_normalize_paramsspskspopstables current_names_table(sselfs current_namespskstable((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _init_0col­s   cOs|i||ƒ\}}|idtƒp|i|_|i ƒ|_ d|jo)|idƒ|_ |i d|i ƒn |i |_ |SdS(Nstables current_namesname(sselfs_init_normalize_paramsspskspopsNonescolstables_tablescopys result_columns current_names setdefaultsname(sselfscolspsk((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _init_1col³s  cOsô|i||ƒ\}}|iƒ|_|idtƒp|i p|i |_ |i |_ x\dddddfD]E}t||tƒ}t||tƒ|jo|i||ƒqrqrW|i|i|iƒ o|id|iƒn|SdS(Nstablesnamesnullablesdefaults primary_keys foreign_keystype(sselfs_init_normalize_paramsspsks start_colscopys result_columnspopsNonestablesend_cols_tablesnames current_nameskeysgetattrsvals setdefaultscolumn_types_eqstype(sselfs start_colsend_colspskskeysval((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _init_2col¾s) cCsnt|ƒ}t|ƒo|id|idƒƒnt|ƒo|id|idƒƒn||fSdS(Nsnameistype(slistspslensks setdefaultspop(sselfspsk((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys_init_normalize_paramsÊs    cCskxd|iD]Y}||joF||||build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _set_diffsÒs   cCsxt||iƒ}|pt||iƒ}|ot|tiiƒo(t|dt ƒt|dt ƒj}n|SdS(Nslength( s isinstancesthissthats __class__srets sqlalchemystypessStringsgetattrsNone(sselfsthissthatsret((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pyscolumn_types_eqØs (cCs|i|ƒSdS(N(svisitors visit_columnsself(sselfsvisitor((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pysaccept_schema_visitoràs(s__name__s __module__s__doc__s__init__s diff_keyss_get_table_namespropertys table_names _get_tablestables _init_0cols _init_1cols _init_2cols_init_normalize_paramss _set_diffsscolumn_types_eqsaccept_schema_visitor(((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _ColumnDeltays          sChangesetTablecBsVtZdZd„Zd„Zd„Zd„Zd„Zd„Ze ed„ƒZ RS(s*Changeset extensions to SQLAlchemy tables.cCsDt|tiƒ ot|it|ƒƒ}n|id|ƒdS(sCreates a column The column parameter may be a column definition or the name of a column in this table. stableN( s isinstancescolumns sqlalchemysColumnsgetattrsselfscsstrscreate(sselfscolumn((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys create_columnåscCsvt|tiƒ oNyt|it|ƒtƒ}Wqbt j otit|ƒƒ}qbXn|i d|ƒdS(s,Drop a column, given its name or definition.stableN( s isinstancescolumns sqlalchemysColumnsgetattrsselfscsstrsNonesAttributeErrorsdrop(sselfscolumn((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys drop_columnïscCsti|i|iƒSdS(N(sschemas_get_table_keysselfsname(sself((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _meta_keyüscCs7|iƒ}|i}||ijo|i|=ndS(s#Remove this table from its metadataN(sselfs _meta_keyskeysmetadatasmetastables(sselfsmetaskey((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys deregisterþs   cOsg|i}|ii}t||ƒ}t|||||Ž|i }|i ƒ||_|i|ƒdS(siRename this table This changes both the database name and the name of this Python object N(sselfsenginesdialects schemachangersvisitorcallables _WrapRenamesnamesparams_engine_run_visitorsargsskwargssmetadatasmetas deregisters _set_parent(sselfsnamesargsskwargssenginesparamsmetasvisitorcallable((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pysrenames     cCs;|itj od|i|if}n |i}|SdS(s$Fullname should always be up to dates%s.%sN(sselfsschemasNonesnamesret(sselfsret((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys _get_fullnames  cCstS(N(sNone(sselfsval((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pyss( s__name__s __module__s__doc__s create_columns drop_columns _meta_keys deregistersrenames _get_fullnamespropertysfullname(((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pysChangesetTableãs     sChangesetColumncBs/tZdZd„Zed„Zed„ZRS(s*Changeset extensions to SQLAlchemy columnscOst|||ŽSdS(s?Alter a column's definition: ALTER TABLE ALTER COLUMN May supply a new column object, or a list of properties to change. For example; the following are equivalent: col.alter(Column('myint',Integer,nullable=False)) col.alter('myint',Integer,nullable=False) col.alter(name='myint',type=Integer,nullable=False) Column name, type, default, and nullable may be changed here. Note that for column defaults, only PassiveDefaults are managed by the database - changing others doesn't make sense. N(s alter_columnsselfspsk(sselfspsk((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pysalter!s cOsBt||ƒ}|i}|ii}|i||||Ž|SdS(sCreate this column in the database. Assumes the given table exists. ALTER TABLE ADD COLUMN, for most databases. N( s_normalize_tablesselfstablesenginesdialectscolumngeneratorsvisitorcallables _run_visitorsargsskwargs(sselfstablesargsskwargssenginesvisitorcallable((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pyscreate0s   cOsBt||ƒ}|i}|ii}|i||||Ž|SdS(s|Drop this column from the database, leaving its table intact. ALTER TABLE DROP COLUMN, for most databases. N( s_normalize_tablesselfstablesenginesdialects columndroppersvisitorcallables _run_visitorsargsskwargs(sselfstablesargsskwargssenginesvisitorcallable((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pysdrop:s   (s__name__s __module__s__doc__saltersNonescreatesdrop(((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pysChangesetColumns   sChangesetIndexcBstZdZd„ZRS(s*Changeset extensions to SQLAlchemy IndexescOsJ|ii}|ii}t||ƒ}t |||||Ž||_dS(smChange the name of an index. This changes both the Python object name and the database name. N( sselfstablesenginesdialects schemachangersvisitorcallables _WrapRenamesnamesparams_engine_run_visitorsargsskwargs(sselfsnamesargsskwargssenginesparamsvisitorcallable((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pysrenameJs   (s__name__s __module__s__doc__srename(((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pysChangesetIndexHs cCsEd}|iƒ oti||iƒiƒƒo|iƒndS(s¨when no Transaction is present, this is called after executions to provide "autocommit" behavior. This adds autocommit after ALTER TABLE statements as well s&UPDATE|INSERT|CREATE|DELETE|DROP|ALTERN( spatsselfsin_transactionsresmatchs statementslstripsuppers _commit_impl(sselfs statementspat((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys_autocommit_hackVs-cCs¢ttiii_tiiit f7_tii it f7_tii it f7_dk}tiƒtiƒx$|iD]}t||ƒiƒqWdS(s<All the 'ugly' operations that patch SQLAlchemy's internals.N(s_autocommit_hacks sqlalchemysenginesbases Connections _autocommitsschemasTables __bases__sChangesetTablesColumnsChangesetColumnsIndexsChangesetIndexs databasessansisqls_patchs constraints__all__sdbsgetattr(sdbs databases((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys_patch`s    (sres sqlalchemys databasessansisqls constraintsNones create_columns drop_columns _to_tables _to_indexs rename_tables rename_indexs_engine_run_visitors alter_columns_normalize_tablesobjects _WrapRenamesdicts _ColumnDeltasChangesetTablesChangesetColumnsChangesetIndexs_autocommit_hacks_patch(s _WrapRenamesansisqls_normalize_tables rename_tables rename_indexs_autocommit_hacksres _to_indexs sqlalchemys create_columns _ColumnDeltasChangesetTables drop_columnsChangesetColumns alter_columnsChangesetIndexs _to_tables_engine_run_visitors_patch((s>build/bdist.darwin-8.0.1-x86/egg/migrate/changeset/__init__.pys?s*         % j<) PK —ƒ5püìùmigrate/changeset/constraint.pyimport sqlalchemy from sqlalchemy import schema class ConstraintChangeset(object): def _normalize_columns(self,cols,fullname=False): """Given: column objects or names; return col names and (maybe) a table""" colnames = [] table = None for col in cols: if isinstance(col,schema.Column): if col.table is not None and table is None: table = col.table if fullname: col = '.'.join((col.table.name,col.name)) else: col = col.name colnames.append(col) return colnames,table def create(self,engine=None): if engine is None: engine = self.engine engine.create(self) def drop(self,engine=None): if engine is None: engine = self.engine #if self.name is None: # self.name = self.autoname() engine.drop(self) def _derived_metadata(self): return self.table._derived_metadata() def accept_schema_visitor(self,visitor,*p,**k): raise NotImplementedError() def _accept_schema_visitor(self,visitor,func,*p,**k): """Call the visitor only if it defines the given function""" try: func = getattr(visitor,func) except AttributeError: return return func(self) def autoname(self): raise NotImplementedError() class PrimaryKeyConstraint(ConstraintChangeset,schema.PrimaryKeyConstraint): def __init__(self,*cols,**kwargs): colnames,table = self._normalize_columns(cols) table = kwargs.pop('table',table) super(PrimaryKeyConstraint,self).__init__(*colnames,**kwargs) if table is not None: self._set_parent(table) def _set_parent(self,table): self.table = table return super(ConstraintChangeset,self)._set_parent(table) 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) self.columns.clear() return ret def accept_schema_visitor(self,visitor,*p,**k): #return visitor.visit_constraint(self,*p,**k) func = 'visit_migrate_primary_key_constraint' return self._accept_schema_visitor(visitor,func,*p,**k) class ForeignKeyConstraint(ConstraintChangeset,schema.ForeignKeyConstraint): def __init__(self,columns,refcolumns,*p,**k): colnames,table = self._normalize_columns(columns) table = k.pop('table',table) refcolnames,reftable = self._normalize_columns(refcolumns,fullname=True) super(ForeignKeyConstraint,self).__init__(colnames,refcolnames,*p,**k) if table is not None: self._set_parent(table) def _get_referenced(self): return [e.column for e in self.elements] referenced = property(_get_referenced) def _get_reftable(self): return self.referenced[0].table reftable = property(_get_reftable) def autoname(self): """Mimic the database's automatic constraint names""" ret = "%(table)s_%(reftable)s_fkey"%dict( table=self.table.name, reftable=self.reftable.name, ) return ret def accept_schema_visitor(self,visitor,*p,**k): func = 'visit_migrate_foreign_key_constraint' return self._accept_schema_visitor(visitor,func,*p,**k) def _patch(): pass PK —ƒ5©R²55'migrate/changeset/databases/__init__.py__all__=[ 'postgres', 'sqlite', 'mysql', 'oracle', ] PKYN58:$ú‘pp&migrate/changeset/databases/sqlite.pyc;ò &dsEc@sßdklZlZlZdklZdkZdklZdeiei fd„ƒYZ dei fd„ƒYZ dei fd „ƒYZd eifd „ƒYZd efd „ƒYZdefd„ƒYZd„ZdS((sansisqlsutils constraint(ssqliteN(s exceptionssSQLiteColumnGeneratorcBstZRS(N(s__name__s __module__(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pysSQLiteColumnGeneratorssSQLiteColumnDroppercBstZd„ZRS(NcCstidƒ‚dS(NsSSQLite does not support DROP COLUMN; see http://www.sqlite.org/lang_altertable.html(s exceptionssNotSupportedError(sselfscolumn((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys visit_column s(s__name__s __module__s visit_column(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pysSQLiteColumnDropperssSQLiteSchemaChangercBs>tZd„Zd„Zd„Zd„Zd„Zd„ZRS(NcCstid|ƒ‚dS(NsJSQLite does not support %s; see http://www.sqlite.org/lang_altertable.html(s exceptionssNotSupportedErrorsop(sselfsop((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys_not_supported scCs|idƒSdS(Ns ALTER TABLE(sselfs_not_supported(sselfs table_namescol_namesdelta((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys_visit_column_nullablescCs|idƒSdS(Ns ALTER TABLE(sselfs_not_supported(sselfs table_namescol_namesdelta((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys_visit_column_defaultscCs|idƒSdS(Ns ALTER TABLE(sselfs_not_supported(sselfs table_namescol_namesdelta((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys_visit_column_typescCs|idƒSdS(Ns ALTER TABLE(sselfs_not_supported(sselfs table_namescol_namesdelta((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys_visit_column_namescCs|idƒdS(Ns ALTER INDEX(sselfs_not_supported(sselfsparam((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys visit_indexs(s__name__s __module__s_not_supporteds_visit_column_nullables_visit_column_defaults_visit_column_types_visit_column_names visit_index(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pysSQLiteSchemaChanger s      sSQLiteConstraintGeneratorcBstZd„ZRS(Nc Csd}digi}|iD]}||iƒq~ƒ}|i i}|i}||||f}|i|ƒ|i ƒdS(Ns#CREATE UNIQUE INDEX %s ON %s ( %s )s,(stmplsjoinsappends_[1]s constraintscolumnsscsnamescolsstablestnamesmsgsselfsexecute( sselfs constraintstmplscsnamescolss_[1]smsgstname((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys$visit_migrate_primary_key_constraints6   (s__name__s __module__s$visit_migrate_primary_key_constraint(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pysSQLiteConstraintGeneratorssSQLiteConstraintDroppercBstZd„ZRS(NcCs4d}|i}||}|i|ƒ|iƒdS(NsDROP INDEX %s (stmpls constraintsnamesmsgsselfsappendsexecute(sselfs constraintsmsgstmplsname((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys$visit_migrate_primary_key_constraint$s    (s__name__s __module__s$visit_migrate_primary_key_constraint(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pysSQLiteConstraintDropper#ssSQLiteDialectChangesetcBstZeZeZeZRS(N(s__name__s __module__sSQLiteColumnGeneratorscolumngeneratorsSQLiteColumnDroppers columndroppersSQLiteSchemaChangers schemachanger(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pysSQLiteDialectChangeset+scCs?tititƒtiitf7_titit ƒdS(N( sutils prepend_basessqlites SQLiteDialectsSQLiteDialectChangesetsSQLiteSchemaGenerators __bases__sSQLiteConstraintGeneratorsSQLiteSchemaDroppersSQLiteConstraintDropper(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys_patch0s(smigrate.changesetsansisqlsutils constraintssqlalchemy.databasesssqlites sqlalchemys exceptionssSQLiteSchemaGeneratorsANSIColumnGeneratorsSQLiteColumnGeneratorsANSIColumnDroppersSQLiteColumnDroppersANSISchemaChangersSQLiteSchemaChangersANSIConstraintGeneratorsSQLiteConstraintGeneratorsobjectsSQLiteConstraintDroppersSQLiteDialectChangesets_patch( sSQLiteDialectChangesetssqlites sqlalchemysSQLiteColumnGenerators constraintsSQLiteConstraintGeneratorsSQLiteSchemaChangersutilsansisqlsSQLiteColumnDroppers exceptionssSQLiteConstraintDroppers_patch((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/sqlite.pys?s    PK —ƒ5^HMÊØØ%migrate/changeset/databases/sqlite.pyfrom migrate.changeset import ansisql,util,constraint from sqlalchemy.databases import sqlite import sqlalchemy from migrate.changeset import exceptions class SQLiteColumnGenerator(sqlite.SQLiteSchemaGenerator,ansisql.ANSIColumnGenerator): pass class SQLiteColumnDropper(ansisql.ANSIColumnDropper): def visit_column(self,column): raise exceptions.NotSupportedError("SQLite does not support " "DROP COLUMN; see http://www.sqlite.org/lang_altertable.html") class SQLiteSchemaChanger(ansisql.ANSISchemaChanger): def _not_supported(self,op): raise exceptions.NotSupportedError("SQLite does not support " "%s; see http://www.sqlite.org/lang_altertable.html"%op) def _visit_column_nullable(self,table_name,col_name,delta): return self._not_supported('ALTER TABLE') def _visit_column_default(self,table_name,col_name,delta): return self._not_supported('ALTER TABLE') def _visit_column_type(self,table_name,col_name,delta): return self._not_supported('ALTER TABLE') def _visit_column_name(self,table_name,col_name,delta): return self._not_supported('ALTER TABLE') def visit_index(self,param): self._not_supported('ALTER INDEX') class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator): def visit_migrate_primary_key_constraint(self,constraint): tmpl = "CREATE UNIQUE INDEX %s ON %s ( %s )" cols = ','.join([c.name for c in constraint.columns]) tname = constraint.table.name name = constraint.name msg = tmpl%(name,tname,cols) self.append(msg) self.execute() class SQLiteConstraintDropper(object): def visit_migrate_primary_key_constraint(self,constraint): tmpl = "DROP INDEX %s " name = constraint.name msg = tmpl%(name) self.append(msg) self.execute() class SQLiteDialectChangeset(object): columngenerator = SQLiteColumnGenerator columndropper = SQLiteColumnDropper schemachanger = SQLiteSchemaChanger def _patch(): util.prepend_base(sqlite.SQLiteDialect,SQLiteDialectChangeset) sqlite.SQLiteSchemaGenerator.__bases__ += (SQLiteConstraintGenerator,) util.prepend_base(sqlite.SQLiteSchemaDropper,SQLiteConstraintDropper) PKZN58dB­! ! (migrate/changeset/databases/postgres.pyc;ò &dsEc@sÏdklZlZdklZdkZdeieifd„ƒYZdei fd„ƒYZ dei fd„ƒYZ d ei fd „ƒYZd eifd „ƒYZd efd„ƒYZd„ZdS((sansisqlsutil(spostgresNsPGColumnGeneratorcBstZRS(N(s__name__s __module__(((sHbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/postgres.pysPGColumnGeneratorssPGColumnDroppercBstZRS(N(s__name__s __module__(((sHbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/postgres.pysPGColumnDropperssPGSchemaChangercBstZRS(N(s__name__s __module__(((sHbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/postgres.pysPGSchemaChanger ssPGConstraintGeneratorcBstZRS(N(s__name__s __module__(((sHbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/postgres.pysPGConstraintGenerator ssPGConstraintDroppercBstZRS(N(s__name__s __module__(((sHbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/postgres.pysPGConstraintDropper ssPGDialectChangesetcBstZeZeZeZRS(N(s__name__s __module__sPGColumnGeneratorscolumngeneratorsPGColumnDroppers columndroppersPGSchemaChangers schemachanger(((sHbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/postgres.pysPGDialectChangesetscCsAtititƒtiitf7_tiit f7_dS(N( sutils prepend_basespostgress PGDialectsPGDialectChangesetsPGSchemaGenerators __bases__sPGConstraintGeneratorsPGSchemaDroppersPGConstraintDropper(((sHbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/postgres.pys_patchs(smigrate.changesetsansisqlsutilssqlalchemy.databasesspostgress sqlalchemysPGSchemaGeneratorsANSIColumnGeneratorsPGColumnGeneratorsANSIColumnDroppersPGColumnDroppersANSISchemaChangersPGSchemaChangersANSIConstraintGeneratorsPGConstraintGeneratorsANSIConstraintDroppersPGConstraintDroppersobjectsPGDialectChangesets_patch( sPGColumnDroppers sqlalchemyspostgressPGConstraintDroppers_patchsutilsansisqlsPGConstraintGeneratorsPGDialectChangesetsPGColumnGeneratorsPGSchemaChanger((sHbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/postgres.pys?s  PKYN581®b &migrate/changeset/databases/oracle.pyc;ò &dsEc@s÷dklZlZlZdklZdkZdeieifd„ƒYZ dei fd„ƒYZ deiei fd„ƒYZ d efd „ƒYZd eeifd „ƒYZd eeifd„ƒYZdefd„ƒYZd„ZdS((sansisqlsutils exceptions(soracleNsOracleColumnGeneratorcBstZRS(N(s__name__s __module__(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pysOracleColumnGeneratorssOracleColumnDroppercBstZRS(N(s__name__s __module__(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pysOracleColumnDropperssOracleSchemaChangercBs#tZd„Zd„Zd„ZRS(NcKsf|idtƒ}|o|i}t|_ntt |ƒi ||}|o ||_n|SdS(Nsoverride_nullable( skwargsspopsNonesoverride_nullablescolumnsnullablesorigsTruessupersOracleSchemaChangersselfsget_column_specificationsret(sselfscolumnskwargssretsoverride_nullablesorig((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pysget_column_specification s   cCsr|iƒ}d|jpd|jp d|jo|i||iƒnd|jo|i||iƒndS(Nstypesnullablesdefaultsname(sdeltaskeyssselfs _run_subvisits_visit_column_changes_visit_column_name(sselfsdeltaskeys((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pys visit_columns  ' c Cs?t|dƒ otidƒ‚n|i}|itjod|iƒj}|i od|iƒj}|i od|iƒj}|ot it iiƒƒ|_n|o t|_ n|i|d|ƒ}|o|d7}n|o t|_ n|o t|_n|i|ƒ|idƒ|i|ƒdS(Ns result_columns&A column object is required to do thissdefaultsnullablesoverride_nullables NULLsMODIFY (shasattrsdeltas exceptionssNotSupportedErrors result_columnscolumnsdefaultsNoneskeyssdropdefault_hacksnullables notnull_hacks null_hacks sqlalchemysPassiveDefaultsfuncsnullsTruesselfsget_column_specificationscolspecsFalsesstart_alter_tables table_namesappend( sselfs table_namescol_namesdeltas null_hackscolumnscolspecs notnull_hacksdropdefault_hack((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pys_visit_column_changes( "     (s__name__s __module__sget_column_specifications visit_columns_visit_column_change(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pysOracleSchemaChanger s sOracleConstraintCommoncBstZd„ZRS(NcCs)|i otidƒ‚n|iSdS(Ns1Oracle constraint names must be explicitly stated(sconssnames exceptionssNotSupportedError(sselfscons((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pysget_constraint_name>s (s__name__s __module__sget_constraint_name(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pysOracleConstraintCommon=ssOracleConstraintGeneratorcBstZRS(N(s__name__s __module__(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pysOracleConstraintGeneratorDssOracleConstraintDroppercBstZRS(N(s__name__s __module__(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pysOracleConstraintDropperFssOracleDialectChangesetcBstZeZeZeZRS(N(s__name__s __module__sOracleColumnGeneratorscolumngeneratorsOracleColumnDroppers columndroppersOracleSchemaChangers schemachanger(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pysOracleDialectChangesetIscCsAtititƒtiitf7_tiit f7_dS(N( sutils prepend_basesoracles OracleDialectsOracleDialectChangesetsOracleSchemaGenerators __bases__sOracleConstraintGeneratorsOracleSchemaDroppersOracleConstraintDropper(((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pys_patchNs(smigrate.changesetsansisqlsutils exceptionsssqlalchemy.databasessoracles sqlalchemysOracleSchemaGeneratorsANSIColumnGeneratorsOracleColumnGeneratorsANSIColumnDroppersOracleColumnDroppersANSISchemaChangersOracleSchemaChangersobjectsOracleConstraintCommonsANSIConstraintGeneratorsOracleConstraintGeneratorsANSIConstraintDroppersOracleConstraintDroppersOracleDialectChangesets_patch( sOracleColumnGenerators sqlalchemysOracleConstraintDroppersOracleColumnDroppersutilsoraclesOracleDialectChangesetsOracleConstraintGeneratorsansisqlsOracleConstraintCommons exceptionssOracleSchemaChangers_patch((sFbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/oracle.pys?s  4PK —ƒ5>á3v$$%migrate/changeset/databases/oracle.pyfrom migrate.changeset import ansisql,util,exceptions from sqlalchemy.databases import oracle import sqlalchemy class OracleColumnGenerator(oracle.OracleSchemaGenerator,ansisql.ANSIColumnGenerator): pass class OracleColumnDropper(ansisql.ANSIColumnDropper): pass class OracleSchemaChanger(oracle.OracleSchemaGenerator,ansisql.ANSISchemaChanger): def get_column_specification(self,column,**kwargs): # Ignore the NOT NULL generated override_nullable = kwargs.pop('override_nullable',None) if override_nullable: orig = column.nullable column.nullable = True ret=super(OracleSchemaChanger,self).get_column_specification(column,**kwargs) if override_nullable: column.nullable = orig return ret def visit_column(self,delta): keys = delta.keys() if 'type' in keys or 'nullable' in keys or 'default' in keys: self._run_subvisit(delta,self._visit_column_change) if 'name' in keys: self._run_subvisit(delta,self._visit_column_name) def _visit_column_change(self,table_name,col_name,delta): if not hasattr(delta,'result_column'): # Oracle needs the whole column definition, not just a lone name/type raise exceptions.NotSupportedError( "A column object is required to do this") column = delta.result_column # Oracle cannot drop a default once created, but it can set it to null. # We'll do that if default=None # http://forums.oracle.com/forums/message.jspa?messageID=1273234#1273234 dropdefault_hack = (column.default is None and 'default' in delta.keys()) # Oracle apparently doesn't like it when we say "not null" if the # column's already not null. Fudge it, so we don't need a new function notnull_hack = ((not column.nullable) and ('nullable' not in delta.keys())) # We need to specify NULL if we're removing a NOT NULL constraint null_hack = (column.nullable and ('nullable' in delta.keys())) if dropdefault_hack: #column.default = sqlalchemy.PassiveDefault("NULL") column.default = sqlalchemy.PassiveDefault(sqlalchemy.func.null()) if notnull_hack: column.nullable = True colspec=self.get_column_specification(column,override_nullable=null_hack) if null_hack: colspec += ' NULL' if notnull_hack: column.nullable = False if dropdefault_hack: column.default = None self.start_alter_table(table_name) self.append("MODIFY ") self.append(colspec) class OracleConstraintCommon(object): def get_constraint_name(self,cons): # Oracle constraints can't guess their name like other DBs if not cons.name: raise exceptions.NotSupportedError( "Oracle constraint names must be explicitly stated") return cons.name class OracleConstraintGenerator(OracleConstraintCommon,ansisql.ANSIConstraintGenerator): pass class OracleConstraintDropper(OracleConstraintCommon,ansisql.ANSIConstraintDropper): pass class OracleDialectChangeset(object): columngenerator = OracleColumnGenerator columndropper = OracleColumnDropper schemachanger = OracleSchemaChanger def _patch(): util.prepend_base(oracle.OracleDialect,OracleDialectChangeset) oracle.OracleSchemaGenerator.__bases__ += (OracleConstraintGenerator,) oracle.OracleSchemaDropper.__bases__ += (OracleConstraintDropper,) PK —ƒ5¼ƒ;Õ Õ $migrate/changeset/databases/mysql.pyfrom migrate.changeset import ansisql,util,exceptions from sqlalchemy.databases import mysql import sqlalchemy class MySQLColumnGenerator(mysql.MySQLSchemaGenerator,ansisql.ANSIColumnGenerator): pass class MySQLColumnDropper(ansisql.ANSIColumnDropper): pass class MySQLSchemaChanger(mysql.MySQLSchemaGenerator,ansisql.ANSISchemaChanger): def visit_column(self,delta): keys = delta.keys() if 'type' in keys or 'nullable' in keys or 'name' in keys: self._run_subvisit(delta,self._visit_column_change) if 'default' in keys: # Column name might have changed above col_name = delta.get('name',delta.current_name) self._run_subvisit(delta,self._visit_column_default,col_name=col_name) def _visit_column_change(self,table_name,col_name,delta): if not hasattr(delta,'result_column'): # Mysql needs the whole column definition, not just a lone name/type raise exceptions.NotSupportedError( "A column object is required to do this") column = delta.result_column colspec = self.get_column_specification(column) self.start_alter_table(table_name) self.append("CHANGE COLUMN ") self.append(col_name) self.append(' ') self.append(colspec) def visit_index(self,param): # If MySQL can do this, I can't find how raise exceptions.NotSupportedError("MySQL cannot rename indexes") class MySQLConstraintGenerator(ansisql.ANSIConstraintGenerator): pass class MySQLConstraintDropper(ansisql.ANSIConstraintDropper): #def visit_constraint(self,constraint): # if isinstance(constraint,sqlalchemy.schema.PrimaryKeyConstraint): # return self._visit_constraint_pk(constraint) # elif isinstance(constraint,sqlalchemy.schema.ForeignKeyConstraint): # return self._visit_constraint_fk(constraint) # return super(MySQLConstraintDropper,self).visit_constraint(constraint) def visit_migrate_primary_key_constraint(self,constraint): self.start_alter_table(constraint) self.append("DROP PRIMARY KEY") self.execute() def visit_migrate_foreign_key_constraint(self,constraint): self.start_alter_table(constraint) self.append("DROP FOREIGN KEY ") self.append(constraint.name) self.execute() class MySQLDialectChangeset(object): columngenerator = MySQLColumnGenerator columndropper = MySQLColumnDropper schemachanger = MySQLSchemaChanger def _patch(): util.prepend_base(mysql.MySQLDialect,MySQLDialectChangeset) mysql.MySQLSchemaGenerator.__bases__ += (MySQLConstraintGenerator,) mysql.MySQLSchemaDropper.__bases__ += (MySQLConstraintDropper,) PKYN58Þ¶èH¶¶%migrate/changeset/databases/mysql.pyc;ò &dsEc@sÛdklZlZlZdklZdkZdeieifd„ƒYZ dei fd„ƒYZ deiei fd„ƒYZ d eifd „ƒYZd eifd „ƒYZd efd„ƒYZd„ZdS((sansisqlsutils exceptions(smysqlNsMySQLColumnGeneratorcBstZRS(N(s__name__s __module__(((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pysMySQLColumnGeneratorssMySQLColumnDroppercBstZRS(N(s__name__s __module__(((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pysMySQLColumnDropperssMySQLSchemaChangercBs#tZd„Zd„Zd„ZRS(NcCs|iƒ}d|jpd|jp d|jo|i||iƒnd|jo2|id|iƒ}|i||id|ƒndS(Nstypesnullablesnamesdefaultscol_name( sdeltaskeyssselfs _run_subvisits_visit_column_changesgets current_namescol_names_visit_column_default(sselfsdeltaskeysscol_name((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pys visit_column s  ' cCst|dƒ otidƒ‚n|i}|i|ƒ}|i |ƒ|i dƒ|i |ƒ|i dƒ|i |ƒdS(Ns result_columns&A column object is required to do thissCHANGE COLUMN s ( shasattrsdeltas exceptionssNotSupportedErrors result_columnscolumnsselfsget_column_specificationscolspecsstart_alter_tables table_namesappendscol_name(sselfs table_namescol_namesdeltascolumnscolspec((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pys_visit_column_changes     cCstidƒ‚dS(NsMySQL cannot rename indexes(s exceptionssNotSupportedError(sselfsparam((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pys visit_indexs(s__name__s __module__s visit_columns_visit_column_changes visit_index(((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pysMySQLSchemaChanger s  sMySQLConstraintGeneratorcBstZRS(N(s__name__s __module__(((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pysMySQLConstraintGenerator"ssMySQLConstraintDroppercBstZd„Zd„ZRS(NcCs(|i|ƒ|idƒ|iƒdS(NsDROP PRIMARY KEY(sselfsstart_alter_tables constraintsappendsexecute(sselfs constraint((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pys$visit_migrate_primary_key_constraint+s  cCs8|i|ƒ|idƒ|i|iƒ|iƒdS(NsDROP FOREIGN KEY (sselfsstart_alter_tables constraintsappendsnamesexecute(sselfs constraint((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pys$visit_migrate_foreign_key_constraint0s  (s__name__s __module__s$visit_migrate_primary_key_constraints$visit_migrate_foreign_key_constraint(((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pysMySQLConstraintDropper$s sMySQLDialectChangesetcBstZeZeZeZRS(N(s__name__s __module__sMySQLColumnGeneratorscolumngeneratorsMySQLColumnDroppers columndroppersMySQLSchemaChangers schemachanger(((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pysMySQLDialectChangeset6scCsAtititƒtiitf7_tiit f7_dS(N( sutils prepend_basesmysqls MySQLDialectsMySQLDialectChangesetsMySQLSchemaGenerators __bases__sMySQLConstraintGeneratorsMySQLSchemaDroppersMySQLConstraintDropper(((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pys_patch;s(smigrate.changesetsansisqlsutils exceptionsssqlalchemy.databasessmysqls sqlalchemysMySQLSchemaGeneratorsANSIColumnGeneratorsMySQLColumnGeneratorsANSIColumnDroppersMySQLColumnDroppersANSISchemaChangersMySQLSchemaChangersANSIConstraintGeneratorsMySQLConstraintGeneratorsANSIConstraintDroppersMySQLConstraintDroppersobjectsMySQLDialectChangesets_patch( s sqlalchemysMySQLDialectChangesetsMySQLColumnDroppersMySQLColumnGeneratorsutilsMySQLSchemaChangersansisqlsMySQLConstraintGeneratorsmysqls exceptionss_patchsMySQLConstraintDropper((sEbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/mysql.pys?s  PKYN58~/Whïï(migrate/changeset/databases/__init__.pyc;ò &dsEc@sddddgZdS(spostgresssqlitesmysqlsoracleN(s__all__(s__all__((sHbuild/bdist.darwin-8.0.1-x86/egg/migrate/changeset/databases/__init__.pys?sPK —ƒ5å”õ'''migrate/changeset/databases/postgres.pyfrom migrate.changeset import ansisql,util from sqlalchemy.databases import postgres import sqlalchemy class PGColumnGenerator(postgres.PGSchemaGenerator,ansisql.ANSIColumnGenerator): pass class PGColumnDropper(ansisql.ANSIColumnDropper): pass class PGSchemaChanger(ansisql.ANSISchemaChanger): pass class PGConstraintGenerator(ansisql.ANSIConstraintGenerator): pass class PGConstraintDropper(ansisql.ANSIConstraintDropper): pass class PGDialectChangeset(object): columngenerator = PGColumnGenerator columndropper = PGColumnDropper schemachanger = PGSchemaChanger def _patch(): util.prepend_base(postgres.PGDialect,PGDialectChangeset) postgres.PGSchemaGenerator.__bases__ += (PGConstraintGenerator,) postgres.PGSchemaDropper.__bases__ += (PGConstraintDropper,) PKDN58„Äv v ¤EGG-INFO/SOURCES.txtPK;N58“×2¤¨ EGG-INFO/dependency_links.txtPK;N58ãMº——¤ä EGG-INFO/PKG-INFOPK;N58çD EGG-INFO/requires.txtPK;N58nÉ<ޤó EGG-INFO/top_level.txtPKeN58“×2¤/ EGG-INFO/not-zip-safePK,"8h>dÇMMíc EGG-INFO/scripts/migratePK —ƒ5ÉŒ¤æ migrate/__init__.pyPKZN58f±±¤1migrate/run.pycPK —ƒ5ÑàBZHH¤migrate/run.pyPKVN58Ö1¤¦¦¤ƒmigrate/__init__.pycPKWN58ëá²=ÁÁ!¤[migrate/versioning/exceptions.pycPK —ƒ5¤[.migrate/versioning/__init__.pyPK —ƒ5ü)W,,¤—.migrate/versioning/template.pyPK —ƒ5^Ë`¤ÿ6migrate/versioning/pathed.pyPK —ƒ5æº$¥¥ ¤;>migrate/versioning/exceptions.pyPK —ƒ5Õ¼–†ªª ¤Emigrate/versioning/controlled.pyPK —ƒ5 ­×%%¤Zmigrate/versioning/api.pyPKWN58ÕëzѪª¤Emigrate/versioning/shell.pycPK —ƒ5ä¨nß88 ¤)–migrate/versioning/repository.pyPK —ƒ5.¹y%ññ¤Ÿ¬migrate/versioning/shell.pyPK —ƒ5ðFO{3'3'¤É»migrate/versioning/version.pyPK —ƒ5#×b€€%¤7ãmigrate/versioning/unique_instance.pyPKXN58‘O°”""¤úèmigrate/versioning/cfgparse.pycPKVN58&’ž$¤Yïmigrate/versioning/__init__.pycPKWN58{¥j‰1‰1¤%ðmigrate/versioning/api.pycPK —ƒ5sp¨44¤æ!migrate/versioning/logengine.pyPK —ƒ57;î`ff¤WAmigrate/versioning/cfgparse.pyPKVN58/Ç!¤ùCmigrate/versioning/script/sql.pycPK —ƒ5†ð€œ• • ¤PImigrate/versioning/script/py.pyPK —ƒ5»™äNN%¤"Wmigrate/versioning/script/__init__.pyPK —ƒ5ˆ¥ ¤³Wmigrate/versioning/script/sql.pyPK —ƒ5ò˜Õ¯ ¯ #¤ñZmigrate/versioning/script/script.pyPKVN58™É-èè&¤áemigrate/versioning/script/__init__.pycPK —ƒ5pÂ`)#¤ gmigrate/versioning/script/logsql.pyPK —ƒ5ø½ævff#¤Ïimigrate/versioning/base/__init__.pyPKWN58ùžJ¬¬!¤vjmigrate/versioning/base/const.pycPK —ƒ5’KvGÇÇ!¤almigrate/versioning/base/logger.pyPKWN58÷ÊÊ"¤gmmigrate/versioning/base/logger.pycPK —ƒ5'‘ÏC88 ¤qomigrate/versioning/base/const.pyPKWN58y hË$¤çpmigrate/versioning/base/__init__.pycPK —ƒ5(¤á3v$$%¤æmigrate/changeset/databases/oracle.pyPK —ƒ5¼ƒ;Õ Õ $¤ƒômigrate/changeset/databases/mysql.pyPKYN58Þ¶èH¶¶%¤šÿmigrate/changeset/databases/mysql.pycPKYN58~/Whïï(¤“migrate/changeset/databases/__init__.pycPK —ƒ5å”õ'''¤Èmigrate/changeset/databases/postgres.pyPKLLü4