diff --git a/docs/changelog.rst b/docs/changelog.rst index fc0ece5..09b56ae 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ 0.5.5 ----- +- use Python logging for output, can be shut down by passing ``logging=False`` to :func:`migrate.versioning.shell.main` - `url` parameter can also be an :class:`Engine` instance (this usage is discouraged though sometimes necessary) - added support for SQLAlchemy 0.6 (missing oracle and firebird) by Michael Bayer - alter, create, drop column / rename table / rename index constructs now accept `alter_metadata` parameter. If True, it will modify Column/Table objects according to changes. Otherwise, everything will be untouched. diff --git a/migrate/versioning/api.py b/migrate/versioning/api.py index 65a1ddc..5964d18 100644 --- a/migrate/versioning/api.py +++ b/migrate/versioning/api.py @@ -28,12 +28,14 @@ import sys import inspect import warnings +import logging from migrate.versioning import (exceptions, repository, schema, version, script as script_) # command name conflict from migrate.versioning.util import catch_known_errors, construct_engine +log = logging.getLogger(__name__) __all__ = [ 'help', 'create', @@ -211,14 +213,14 @@ def test(url, repository, **opts): script = repos.version(None).script() # Upgrade - print "Upgrading...", + log.info("Upgrading...") script.run(engine, 1) - print "done" + log.info("done") - print "Downgrading...", + log.info("Downgrading...") script.run(engine, -1) - print "done" - print "Success" + log.info("done") + log.info("Success") def version_control(url, repository, version=None, **opts): @@ -333,13 +335,13 @@ def _migrate(url, repository, version, upgrade, err, **opts): changeset = schema.changeset(version) for ver, change in changeset: nextver = ver + changeset.step - print '%s -> %s... ' % (ver, nextver) + log.info('%s -> %s... ', ver, nextver) if opts.get('preview_sql'): if isinstance(change, PythonScript): - print change.preview_sql(url, changeset.step, **opts) + log.info(change.preview_sql(url, changeset.step, **opts)) elif isinstance(change, SqlScript): - print change.source() + log.info(change.source()) elif opts.get('preview_py'): if not isinstance(change, PythonScript): @@ -349,10 +351,10 @@ def _migrate(url, repository, version, upgrade, err, **opts): module = schema.repository.version(source_ver).script().module funcname = upgrade and "upgrade" or "downgrade" func = getattr(module, funcname) - print inspect.getsource(func) + log.info(inspect.getsource(func)) else: schema.runchange(ver, change, changeset.step) - print 'done' + log.info('done') def _migrate_version(schema, version, upgrade, err): diff --git a/migrate/versioning/base/__init__.py b/migrate/versioning/base/__init__.py index 4c3842a..54a9e0c 100644 --- a/migrate/versioning/base/__init__.py +++ b/migrate/versioning/base/__init__.py @@ -1,5 +1,13 @@ """Things that should be imported by all migrate packages""" -#__all__ = ['logging','log','databases','operations'] -from logger import logging, log -from const import databases, operations +from sqlalchemy.util import OrderedDict + + +__all__ = ['databases', 'operations'] + +databases = ('sqlite', 'postgres', 'mysql', 'oracle', 'mssql', 'firebird') + +# Map operation names to function names +operations = OrderedDict() +operations['upgrade'] = 'upgrade' +operations['downgrade'] = 'downgrade' diff --git a/migrate/versioning/base/const.py b/migrate/versioning/base/const.py deleted file mode 100644 index 7c24245..0000000 --- a/migrate/versioning/base/const.py +++ /dev/null @@ -1,11 +0,0 @@ -from sqlalchemy.util import OrderedDict - - -__all__ = ['databases', 'operations'] - -databases = ('sqlite', 'postgres', 'mysql', 'oracle', 'mssql', 'firebird') - -# Map operation names to function names -operations = OrderedDict() -operations['upgrade'] = 'upgrade' -operations['downgrade'] = 'downgrade' diff --git a/migrate/versioning/base/logger.py b/migrate/versioning/base/logger.py deleted file mode 100644 index 0f97d40..0000000 --- a/migrate/versioning/base/logger.py +++ /dev/null @@ -1,9 +0,0 @@ -"""Manages logging (to stdout) for our versioning system. -""" -import logging - -log=logging.getLogger('migrate.versioning') -log.setLevel(logging.WARNING) -log.addHandler(logging.StreamHandler()) - -__all__ = ['log','logging'] diff --git a/migrate/versioning/genmodel.py b/migrate/versioning/genmodel.py index 114d985..9b8e0bd 100644 --- a/migrate/versioning/genmodel.py +++ b/migrate/versioning/genmodel.py @@ -7,11 +7,13 @@ """ import sys +import logging import migrate import sqlalchemy +log = logging.getLogger(__name__) HEADER = """ ## File autogenerated by genmodel.py diff --git a/migrate/versioning/pathed.py b/migrate/versioning/pathed.py index 6174737..5a6fc41 100644 --- a/migrate/versioning/pathed.py +++ b/migrate/versioning/pathed.py @@ -4,12 +4,15 @@ import os import shutil +import logging from migrate.versioning import exceptions from migrate.versioning.base import * from migrate.versioning.util import KeyedInstance +log = logging.getLogger(__name__) + class Pathed(KeyedInstance): """ A class associated with a path/directory tree. @@ -32,7 +35,7 @@ class Pathed(KeyedInstance): """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)) + log.debug("Getting parent %r:%r" % (self.__class__.parent, parent_path)) self.parent._init_child(path, self) def _init_child(self, child, path): diff --git a/migrate/versioning/repository.py b/migrate/versioning/repository.py index 3eb2f74..a79aa25 100644 --- a/migrate/versioning/repository.py +++ b/migrate/versioning/repository.py @@ -4,6 +4,7 @@ import os import shutil import string +import logging from pkg_resources import resource_string, resource_filename from migrate.versioning import exceptions, script, version, pathed, cfgparse @@ -11,6 +12,8 @@ from migrate.versioning.template import template from migrate.versioning.base import * +log = logging.getLogger(__name__) + class Changeset(dict): """A collection of changes to be applied to a database. @@ -67,13 +70,13 @@ class Repository(pathed.Pathed): _versions = 'versions' def __init__(self, path): - log.info('Loading repository %s...' % path) + log.debug('Loading repository %s...' % path) self.verify(path) super(Repository, self).__init__(path) self.config = cfgparse.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('Repository %s loaded successfully' % path) log.debug('Config: %r' % self.config.to_dict()) @classmethod diff --git a/migrate/versioning/schema.py b/migrate/versioning/schema.py index e98779a..8014bcb 100644 --- a/migrate/versioning/schema.py +++ b/migrate/versioning/schema.py @@ -2,6 +2,7 @@ Database schema version management. """ import sys +import logging from sqlalchemy import (Table, Column, MetaData, String, Text, Integer, create_engine) @@ -15,6 +16,8 @@ from migrate.versioning.util import load_model from migrate.versioning.version import VerNum +log = logging.getLogger(__name__) + class ControlledSchema(object): """A database under version control""" diff --git a/migrate/versioning/schemadiff.py b/migrate/versioning/schemadiff.py index 8a06643..80a6085 100644 --- a/migrate/versioning/schemadiff.py +++ b/migrate/versioning/schemadiff.py @@ -1,9 +1,14 @@ """ Schema differencing support. """ +import logging + import sqlalchemy from migrate.changeset import SQLA_06 + +log = logging.getLogger(__name__) + def getDiffOfModelAgainstDatabase(model, conn, excludeTables=None): """ Return differences of model against database. diff --git a/migrate/versioning/script/base.py b/migrate/versioning/script/base.py index 2fdc5df..e88e59c 100644 --- a/migrate/versioning/script/base.py +++ b/migrate/versioning/script/base.py @@ -1,10 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import logging -from migrate.versioning.base import log, operations +from migrate.versioning.base import operations from migrate.versioning import pathed, exceptions +log = logging.getLogger(__name__) + class BaseScript(pathed.Pathed): """Base class for other types of scripts. All scripts have the following properties: @@ -20,10 +23,10 @@ class BaseScript(pathed.Pathed): """ # TODO: sphinxfy this and implement it correctly def __init__(self, path): - log.info('Loading script %s...' % path) + log.debug('Loading script %s...' % path) self.verify(path) super(BaseScript, self).__init__(path) - log.info('Script %s loaded successfully' % path) + log.debug('Script %s loaded successfully' % path) @classmethod def verify(cls, path): diff --git a/migrate/versioning/script/py.py b/migrate/versioning/script/py.py index 3eaec29..0158779 100644 --- a/migrate/versioning/script/py.py +++ b/migrate/versioning/script/py.py @@ -1,8 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import warnings import shutil +import warnings +import logging from StringIO import StringIO import migrate @@ -12,6 +13,8 @@ from migrate.versioning.template import template from migrate.versioning.script import base from migrate.versioning.util import import_path, load_model, construct_engine + +log = logging.getLogger(__name__) __all__ = ['PythonScript'] class PythonScript(base.BaseScript): diff --git a/migrate/versioning/script/sql.py b/migrate/versioning/script/sql.py index 97dc505..45e7456 100644 --- a/migrate/versioning/script/sql.py +++ b/migrate/versioning/script/sql.py @@ -1,9 +1,12 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import logging from migrate.versioning.script import base +log = logging.getLogger(__name__) + class SqlScript(base.BaseScript): """A file containing plain SQL statements.""" diff --git a/migrate/versioning/shell.py b/migrate/versioning/shell.py index 82a1627..b99cc49 100644 --- a/migrate/versioning/shell.py +++ b/migrate/versioning/shell.py @@ -2,10 +2,12 @@ import sys import inspect +import logging from optparse import OptionParser, BadOptionError -from migrate.versioning.base import * from migrate.versioning import api, exceptions +from migrate.versioning.base import * +from migrate.versioning.util import asbool alias = dict( @@ -50,10 +52,14 @@ class PassiveOptionParser(OptionParser): del rargs[0] def main(argv=None, **kwargs): - """kwargs are default options that can be overriden with passing - --some_option to cmdline - """ + """Shell interface to :mod:`migrate.versioning.api`. + kwargs are default options that can be overriden with passing + --some_option as command line option + + :param logging: Let migrate configure logging + :type logging: bool + """ argv = argv or list(sys.argv[1:]) commands = list(api.__all__) commands.sort() @@ -138,6 +144,17 @@ def main(argv=None, **kwargs): # apply overrides kwargs.update(override_kwargs) + # configure logging + if asbool(kwargs.pop('logging', True)): + logger = logging.getLogger() + logger.setLevel(logging.INFO) + formatter = logging.Formatter("%(message)s") + ch = logging.StreamHandler(sys.stdout) + ch.setFormatter(formatter) + logger.addHandler(ch) + + log = logging.getLogger(__name__) + # check if all args are given try: num_defaults = len(f_defaults) @@ -153,7 +170,7 @@ def main(argv=None, **kwargs): try: ret = command_func(**kwargs) if ret is not None: - print ret + log.info(ret) except (exceptions.UsageError, exceptions.KnownError), e: parser.error(e.args[0]) diff --git a/migrate/versioning/version.py b/migrate/versioning/version.py index 92e9f19..eb7ab64 100644 --- a/migrate/versioning/version.py +++ b/migrate/versioning/version.py @@ -4,10 +4,13 @@ import os import re import shutil +import logging from migrate.versioning import exceptions, pathed, script +log = logging.getLogger(__name__) + class VerNum(object): """A version number that behaves like a string and int at the same time""" diff --git a/test/versioning/test_shell.py b/test/versioning/test_shell.py index d9e3364..0cb0b1a 100644 --- a/test/versioning/test_shell.py +++ b/test/versioning/test_shell.py @@ -31,6 +31,16 @@ class TestShellCommands(Shell): self.assertTrue(result.stdout) self.assertFalse(result.stderr) + def test_shutdown_logging(self): + """Try to shutdown logging output""" + repos = self.tmp_repos() + result = self.env.run('migrate create %s repository_name' % repos) + result = self.env.run('migrate version %s --logging=False' % repos) + self.assertEqual(result.stdout, '') + + # TODO: assert logging messages to 0 + shell.main(['version', repos], logging=False) + def test_main(self): """Test main() function""" # TODO: test output?