From 2fe569dc6954b0b6c953b94fe0354ac9374f65ef Mon Sep 17 00:00:00 2001 From: iElectric Date: Mon, 8 Jun 2009 19:05:27 +0000 Subject: [PATCH] update README, add docs to repository.py and schema.py --- README | 25 +++++--------- docs/api.rst | 25 +++++++++----- migrate/versioning/repository.py | 56 ++++++++++++++++++-------------- migrate/versioning/schema.py | 26 ++++++++------- migrate/versioning/version.py | 9 +++-- 5 files changed, 77 insertions(+), 64 deletions(-) diff --git a/README b/README index 3bbce04..7ad5929 100644 --- a/README +++ b/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 `_. 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 `_. 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 `_ +and at the Python package index `sqlalchemy-migrate `_. -Homepage is located at [5] +Homepage is located at `code.google.com `_ -[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 `_ 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 `_ diff --git a/docs/api.rst b/docs/api.rst index 6f0a6f2..cd2aefe 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -128,12 +128,12 @@ Module :mod:`schema ` :members: :synopsis: Database schema management -Module :mod:`shell ` ------------------------------------------------- +Module :mod:`schemadiff ` +-------------------------------------------------------- -.. automodule:: migrate.versioning.shell +.. automodule:: migrate.versioning.schemadiff :members: - :synopsis: Shell commands + :synopsis: Database schema and model differencing Module :mod:`script ` ------------------------------------------------ @@ -152,16 +152,23 @@ Module :mod:`script ` :show-inheritance: :inherited-members: +Module :mod:`shell ` +---------------------------------------------- + +.. automodule:: migrate.versioning.shell + :members: + :synopsis: Shell commands + Module :mod:`util ` ------------------------------------------------- +-------------------------------------------- .. automodule:: migrate.versioning.util :members: :synopsis: Utility functions -Module :mod:`schemadiff ` --------------------------------------------------------- +Module :mod:`version ` +-------------------------------------------------- -.. automodule:: migrate.versioning.schemadiff +.. automodule:: migrate.versioning.version :members: - :synopsis: Database schema and model differencing + :synopsis: Version management diff --git a/migrate/versioning/repository.py b/migrate/versioning/repository.py index 30719a1..3eb2f74 100644 --- a/migrate/versioning/repository.py +++ b/migrate/versioning/repository.py @@ -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 ` """ 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()]) diff --git a/migrate/versioning/schema.py b/migrate/versioning/schema.py index 4825310..ae6d6e7 100644 --- a/migrate/versioning/schema.py +++ b/migrate/versioning/schema.py @@ -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): """ diff --git a/migrate/versioning/version.py b/migrate/versioning/version.py index 9c67a8c..9004402 100644 --- a/migrate/versioning/version.py +++ b/migrate/versioning/version.py @@ -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