update README, add docs to repository.py and schema.py
This commit is contained in:
parent
d835658f23
commit
2fe569dc69
25
README
25
README
@ -5,36 +5,29 @@ Migrate extends SQLAlchemy to have database changeset handling. It provides a da
|
||||
Help
|
||||
----
|
||||
|
||||
Sphinx documentation is available at the project page [1].
|
||||
Sphinx documentation is available at the project page `packages.python.org <http://packages.python.org/sqlalchemy-migrate/>`_.
|
||||
|
||||
Users and developers can be found at #sqlalchemy-migrate on Freenode IRC network
|
||||
and at the public users mailing list [2].
|
||||
and at the public users mailing list `migrate-users <http://groups.google.com/group/migrate-users>`_.
|
||||
|
||||
New releases and major changes are announced at the public announce
|
||||
mailing list [3] and at the Python package index [4].
|
||||
mailing list `migrate-announce <http://groups.google.com/group/migrate-announce>`_
|
||||
and at the Python package index `sqlalchemy-migrate <http://pypi.python.org/pypi/sqlalchemy-migrate>`_.
|
||||
|
||||
Homepage is located at [5]
|
||||
Homepage is located at `code.google.com <http://code.google.com/p/sqlalchemy-migrate/>`_
|
||||
|
||||
[1] http://packages.python.org/sqlalchemy-migrate/
|
||||
[2] http://groups.google.com/group/migrate-users
|
||||
[3] http://groups.google.com/group/migrate-announce
|
||||
[4] http://pypi.python.org/pypi/sqlalchemy-migrate
|
||||
[5] http://code.google.com/p/sqlalchemy-migrate/
|
||||
|
||||
Tests and Bugs
|
||||
--------------
|
||||
|
||||
To run automated tests:
|
||||
|
||||
- Copy test_db.cfg.tmpl to test_db.cfg
|
||||
- Edit test_db.cfg with database connection strings suitable for
|
||||
running tests. (Use empty databases.)
|
||||
- Edit test_db.cfg with database connection strings suitable for running tests. (Use empty databases.)
|
||||
- python setup.py test
|
||||
|
||||
Note that nose [5] is required to run migrate's tests. It should be
|
||||
Note that `nose <http://somethingaboutorange.com/mrl/projects/nose/>`_ is required to run migrate's tests. It should be
|
||||
installed automatically; if not, try "easy_install nose".
|
||||
|
||||
Please report any issues with sqlalchemy-migrate to the issue tracker
|
||||
at [6]
|
||||
|
||||
[5] http://somethingaboutorange.com/mrl/projects/nose/
|
||||
[6] http://code.google.com/p/sqlalchemy-migrate/issues/list
|
||||
at `code.google.com issues <http://code.google.com/p/sqlalchemy-migrate/issues/list>`_
|
||||
|
25
docs/api.rst
25
docs/api.rst
@ -128,12 +128,12 @@ Module :mod:`schema <migrate.versioning.schema>`
|
||||
:members:
|
||||
:synopsis: Database schema management
|
||||
|
||||
Module :mod:`shell <migrate.versioning.shell>`
|
||||
------------------------------------------------
|
||||
Module :mod:`schemadiff <migrate.versioning.schemadiff>`
|
||||
--------------------------------------------------------
|
||||
|
||||
.. automodule:: migrate.versioning.shell
|
||||
.. automodule:: migrate.versioning.schemadiff
|
||||
:members:
|
||||
:synopsis: Shell commands
|
||||
:synopsis: Database schema and model differencing
|
||||
|
||||
Module :mod:`script <migrate.versioning.script>`
|
||||
------------------------------------------------
|
||||
@ -152,16 +152,23 @@ Module :mod:`script <migrate.versioning.script>`
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
Module :mod:`shell <migrate.versioning.shell>`
|
||||
----------------------------------------------
|
||||
|
||||
.. automodule:: migrate.versioning.shell
|
||||
:members:
|
||||
:synopsis: Shell commands
|
||||
|
||||
Module :mod:`util <migrate.versioning.util>`
|
||||
------------------------------------------------
|
||||
--------------------------------------------
|
||||
|
||||
.. automodule:: migrate.versioning.util
|
||||
:members:
|
||||
:synopsis: Utility functions
|
||||
|
||||
Module :mod:`schemadiff <migrate.versioning.schemadiff>`
|
||||
--------------------------------------------------------
|
||||
Module :mod:`version <migrate.versioning.version>`
|
||||
--------------------------------------------------
|
||||
|
||||
.. automodule:: migrate.versioning.schemadiff
|
||||
.. automodule:: migrate.versioning.version
|
||||
:members:
|
||||
:synopsis: Database schema and model differencing
|
||||
:synopsis: Version management
|
||||
|
@ -14,11 +14,10 @@ from migrate.versioning.base import *
|
||||
class Changeset(dict):
|
||||
"""A collection of changes to be applied to a database.
|
||||
|
||||
Changesets are bound to a repository and manage a set of logsql
|
||||
Changesets are bound to a repository and manage a set of
|
||||
scripts from that repository.
|
||||
|
||||
Behaves like a dict, for the most part. Keys are ordered based on
|
||||
start/end.
|
||||
Behaves like a dict, for the most part. Keys are ordered based on step value.
|
||||
"""
|
||||
|
||||
def __init__(self, start, *changes, **k):
|
||||
@ -50,11 +49,13 @@ class Changeset(dict):
|
||||
return zip(self.keys(), self.values())
|
||||
|
||||
def add(self, change):
|
||||
"""Add new change to changeset"""
|
||||
key = self.end
|
||||
self.end += self.step
|
||||
self[key] = change
|
||||
|
||||
def run(self, *p, **k):
|
||||
"""Run the changeset scripts"""
|
||||
for version, script in self:
|
||||
script.run(*p, **k)
|
||||
|
||||
@ -119,54 +120,62 @@ class Repository(pathed.Pathed):
|
||||
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')
|
||||
Repository.create_manage_file(manager, repository=path)
|
||||
except:
|
||||
log.error("There was an error creating your repository")
|
||||
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')
|
||||
Repository.create_manage_file(manager, repository=path)
|
||||
|
||||
return cls(path)
|
||||
|
||||
def create_script(self, description, **k):
|
||||
""""""
|
||||
"""API to :meth:`migrate.versioning.version.Collection.create_new_python_version`"""
|
||||
self.versions.create_new_python_version(description, **k)
|
||||
|
||||
def create_script_sql(self, database, **k):
|
||||
""""""
|
||||
"""API to :meth:`migrate.versioning.version.Collection.create_new_sql_version`"""
|
||||
self.versions.create_new_sql_version(database, **k)
|
||||
|
||||
@property
|
||||
def latest(self):
|
||||
""""""
|
||||
"""API to :attr:`migrate.versioning.version.Collection.latest`"""
|
||||
return self.versions.latest
|
||||
|
||||
@property
|
||||
def version_table(self):
|
||||
""""""
|
||||
"""Returns version_table name specified in config"""
|
||||
return self.config.get('db_settings', 'version_table')
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
""""""
|
||||
"""Returns repository id specified in config"""
|
||||
return self.config.get('db_settings', 'repository_id')
|
||||
|
||||
def version(self, *p, **k):
|
||||
""""""
|
||||
"""API to :attr:`migrate.versioning.version.Collection.version`"""
|
||||
return self.versions.version(*p, **k)
|
||||
|
||||
@classmethod
|
||||
def clear(cls):
|
||||
""""""
|
||||
# TODO: deletes repo
|
||||
super(Repository, cls).clear()
|
||||
version.Collection.clear()
|
||||
|
||||
def changeset(self, database, start, end=None):
|
||||
"""Create a changeset to migrate this dbms from ver. start to end/latest.
|
||||
"""Create a changeset to migrate this database from ver. start to end/latest.
|
||||
|
||||
:param database: name of database to generate changeset
|
||||
:param start: version to start at
|
||||
:param end: version to end at (latest if None given)
|
||||
:type database: string
|
||||
:type start: int
|
||||
:type end: int
|
||||
:returns: :class:`Changeset instance <migration.versioning.repository.Changeset>`
|
||||
"""
|
||||
start = version.VerNum(start)
|
||||
|
||||
@ -189,13 +198,12 @@ class Repository(pathed.Pathed):
|
||||
ret = Changeset(start, step=step, *changes)
|
||||
return ret
|
||||
|
||||
|
||||
@classmethod
|
||||
def create_manage_file(cls, file_, **opts):
|
||||
"""Create a project management script (manage.py)
|
||||
|
||||
:param file_: Destination file to be written
|
||||
:param **opts: Options that are passed to template
|
||||
:param opts: Options that are passed to template
|
||||
"""
|
||||
vars_ = ",".join(["%s='%s'" % var for var in opts.iteritems()])
|
||||
|
||||
|
@ -17,25 +17,26 @@ class ControlledSchema(object):
|
||||
|
||||
def __init__(self, engine, repository):
|
||||
if isinstance(repository, str):
|
||||
repository=Repository(repository)
|
||||
repository = Repository(repository)
|
||||
self.engine = engine
|
||||
self.repository = repository
|
||||
self.meta=MetaData(engine)
|
||||
self._load()
|
||||
self.meta = MetaData(engine)
|
||||
self.load()
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Compare two schemas by repositories and versions"""
|
||||
return (self.repository is other.repository \
|
||||
and self.version == other.version)
|
||||
|
||||
def _load(self):
|
||||
def load(self):
|
||||
"""Load controlled schema version info from DB"""
|
||||
tname = self.repository.version_table
|
||||
self.meta=MetaData(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(
|
||||
self.table.c.repository_id == str(self.repository.id)))
|
||||
@ -57,13 +58,15 @@ class ControlledSchema(object):
|
||||
def create(cls, engine, repository, version=None):
|
||||
"""
|
||||
Declare a database to be under a repository's version control.
|
||||
|
||||
:returns: :class:`ControlledSchema`
|
||||
"""
|
||||
# Confirm that the version # is valid: positive, integer,
|
||||
# exists in repos
|
||||
if type(repository) is str:
|
||||
repository=Repository(repository)
|
||||
if isinstance(repository, str):
|
||||
repository = Repository(repository)
|
||||
version = cls._validate_version(repository, version)
|
||||
table=cls._create_table_version(engine, repository, version)
|
||||
table = cls._create_table_version(engine, repository, version)
|
||||
# TODO: history table
|
||||
# Load repository information and return
|
||||
return cls(engine, repository)
|
||||
@ -73,7 +76,7 @@ class ControlledSchema(object):
|
||||
"""
|
||||
Ensures this is a valid version number for this repository.
|
||||
|
||||
:raises: :exc:`cls.InvalidVersionError` if invalid
|
||||
:raises: :exc:`ControlledSchema.InvalidVersionError` if invalid
|
||||
:return: valid version number
|
||||
"""
|
||||
if version is None:
|
||||
@ -164,8 +167,7 @@ class ControlledSchema(object):
|
||||
"""
|
||||
Returns the database name of an engine - ``postgres``, ``sqlite`` ...
|
||||
"""
|
||||
# TODO: This is a bit of a hack...
|
||||
return str(engine.dialect.__module__).split('.')[-1]
|
||||
return engine.name
|
||||
|
||||
def changeset(self, version=None):
|
||||
database = self._engine_db(self.engine)
|
||||
@ -187,7 +189,7 @@ class ControlledSchema(object):
|
||||
and_(self.table.c.version == int(startver),
|
||||
self.table.c.repository_id == str(self.repository.id)))
|
||||
self.engine.execute(update, version=int(endver))
|
||||
self._load()
|
||||
self.load()
|
||||
|
||||
def upgrade(self, version=None):
|
||||
"""
|
||||
|
@ -9,7 +9,7 @@ from migrate.versioning import exceptions, pathed, script
|
||||
|
||||
|
||||
class VerNum(object):
|
||||
"""A version number"""
|
||||
"""A version number that behaves like a string and int at the same time"""
|
||||
|
||||
_instances = dict()
|
||||
|
||||
@ -51,7 +51,9 @@ class Collection(pathed.Pathed):
|
||||
FILENAME_WITH_VERSION = re.compile(r'^(\d{3,}).*')
|
||||
|
||||
def __init__(self, path):
|
||||
"""Collect current version scripts in repository"""
|
||||
"""Collect current version scripts in repository
|
||||
and store them in self.versions
|
||||
"""
|
||||
super(Collection, self).__init__(path)
|
||||
|
||||
# Create temporary list of files, allowing skipped version numbers.
|
||||
@ -79,6 +81,7 @@ class Collection(pathed.Pathed):
|
||||
|
||||
@property
|
||||
def latest(self):
|
||||
""":returns: Latest version in Collection"""
|
||||
return max([VerNum(0)] + self.versions.keys())
|
||||
|
||||
def create_new_python_version(self, description, **k):
|
||||
@ -118,7 +121,7 @@ class Collection(pathed.Pathed):
|
||||
self.versions[ver].add_script(filepath)
|
||||
|
||||
def version(self, vernum=None):
|
||||
"""Returns latest Version if vernum is not given. \
|
||||
"""Returns latest Version if vernum is not given.
|
||||
Otherwise, returns wanted version"""
|
||||
if vernum is None:
|
||||
vernum = self.latest
|
||||
|
Loading…
x
Reference in New Issue
Block a user