summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-04-28 15:47:51 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2010-04-28 15:47:51 -0400
commit54835cc4cd9c5ac65db888b5ec801f9fb12e29cd (patch)
tree709503a00dc53cd33efb7cb4a4c9be4d898555a1
parent92e8f58ffc8709f332d29a7bc75dad212605377a (diff)
downloadalembic-54835cc4cd9c5ac65db888b5ec801f9fb12e29cd.tar.gz
- pushed the whole command line options thing into a single main() function
- command methods now accept a "config" plus positional + kw arguments, for easy API calling - main() provides context sensitive arguments and help for each command using inspect.getargspec()
-rw-r--r--alembic/__init__.py80
-rw-r--r--alembic/command.py59
-rw-r--r--alembic/config.py34
-rw-r--r--alembic/options.py91
-rw-r--r--alembic/script.py10
-rw-r--r--alembic/util.py5
-rw-r--r--tests/__init__.py23
7 files changed, 149 insertions, 153 deletions
diff --git a/alembic/__init__.py b/alembic/__init__.py
index 649da28..568b000 100644
--- a/alembic/__init__.py
+++ b/alembic/__init__.py
@@ -1,18 +1,80 @@
-from alembic import options, command
+from alembic import config, command, util
+from optparse import OptionParser
+import inspect
+import os
__version__ = '0.1alpha'
-
-
def main(argv):
- parser = options.get_option_parser()
+ # TODO:
+ # OK, what's the super option parser library that
+ # allows <command> plus command-specfic sub-options,
+ # and derives everything from callables ?
+ # we're inventing here a bit.
+
+ commands = dict([
+ (fn.__name__, fn) for fn in
+ [getattr(command, n) for n in dir(command)]
+ if inspect.isfunction(fn) and
+ fn.__name__[0] != '_' and
+ fn.__module__ == 'alembic.command'
+ ])
+
+ parser = OptionParser(
+ "usage: %prog [options] <command> [command arguments]\n\n"
+ "Available Commands:\n" +
+ "\n".join(sorted([
+ util.format_opt(fn.__name__.replace('_', '-'), fn.__doc__)
+ for fn in commands.values()
+ ]))
+ )
+ parser.add_option("-c", "--config",
+ type="string",
+ default="alembic.ini",
+ help="Alternate config file")
+ parser.add_option("-t", "--template",
+ default='generic',
+ type="string",
+ help="Setup template for use with 'init'")
+ parser.add_option("-m", "--message",
+ type="string",
+ help="Message string to use with 'revision'")
+
+ cmd_line_options, cmd_line_args = parser.parse_args(argv[1:])
+
+ if len(cmd_line_args) < 1:
+ util.err("no command specified")
+
+ cmd = cmd_line_args.pop(0).replace('-', '_')
+
+ try:
+ cmd_fn = commands[cmd]
+ except KeyError:
+ util.err("no such command %r" % cmd)
+
+ spec = inspect.getargspec(cmd_fn)
+ if spec[3]:
+ positional = spec[0][1:-len(spec[3])]
+ kwarg = spec[0][-len(spec[3]):]
+ else:
+ positional = spec[0][1:]
+ kwarg = []
+
+ kw = dict(
+ (k, getattr(cmd_line_options, k))
+ for k in kwarg
+ )
+
+ if len(cmd_line_args) != len(positional):
+ util.err("Usage: %s %s [options] %s" % (
+ os.path.basename(argv[0]),
+ cmd,
+ " ".join(["<%s>" % p for p in positional])
+ ))
- opt = options.Options(parser, argv)
- cmd = opt.get_command().replace('-', '_')
- if cmd not in dir(command):
- parser.error("no such command %r" % cmd)
- getattr(command, cmd)(opt)
+ cfg = config.Config(cmd_line_options.config)
+ cmd_fn(cfg, *cmd_line_args, **kw)
diff --git a/alembic/command.py b/alembic/command.py
index 50452b0..73e1db8 100644
--- a/alembic/command.py
+++ b/alembic/command.py
@@ -4,13 +4,13 @@ import os
import sys
import uuid
-def list_templates(opts):
+def list_templates(config):
"""List available templates"""
print "Available templates:\n"
- for tempname in os.listdir(opts.get_template_directory()):
+ for tempname in os.listdir(config.get_template_directory()):
readme = os.path.join(
- opts.get_template_directory(),
+ config.get_template_directory(),
tempname,
'README')
synopsis = open(readme).next()
@@ -19,40 +19,39 @@ def list_templates(opts):
print "\nTemplates are used via the 'init' command, e.g.:"
print "\n alembic init --template pylons ./scripts"
-def init(opts):
+def init(config, directory, template='generic'):
"""Initialize a new scripts directory."""
- dir_, = opts.get_command_args(1, 'alembic init <directory>')
- if os.access(dir_, os.F_OK):
- opts.err("Directory %s already exists" % dir_)
+ if os.access(directory, os.F_OK):
+ util.err("Directory %s already exists" % directory)
- util.status("Creating directory %s" % os.path.abspath(dir_),
- os.makedirs, dir_)
+ template_dir = os.path.join(config.get_template_directory(),
+ template)
+ if not os.access(template_dir, os.F_OK):
+ util.err("No such template %r" % template)
+
+ util.status("Creating directory %s" % os.path.abspath(directory),
+ os.makedirs, directory)
- versions = os.path.join(dir_, 'versions')
+ versions = os.path.join(directory, 'versions')
util.status("Creating directory %s" % os.path.abspath(versions),
os.makedirs, versions)
- script = ScriptDirectory(dir_, opts)
+ script = ScriptDirectory(directory)
- template_dir = os.path.join(opts.get_template_directory(),
- opts.cmd_line_options.template)
- if not os.access(template_dir, os.F_OK):
- opts.err("No such template %r" % opts.cmd_line_options.template)
-
for file_ in os.listdir(template_dir):
if file_ == 'alembic.ini.mako':
- config_file = os.path.abspath(opts.cmd_line_options.config)
+ config_file = os.path.abspath(config.config_file_name)
if os.access(config_file, os.F_OK):
util.msg("File %s already exists, skipping" % config_file)
else:
script.generate_template(
os.path.join(template_dir, file_),
config_file,
- script_location=dir_
+ script_location=directory
)
else:
- output_file = os.path.join(dir_, file_)
+ output_file = os.path.join(directory, file_)
script.copy_file(
os.path.join(template_dir, file_),
output_file
@@ -61,34 +60,34 @@ def init(opts):
util.msg("Please edit configuration/connection/logging "\
"settings in %r before proceeding." % config_file)
-def revision(opts):
+def revision(config, message=None):
"""Create a new revision file."""
- script = ScriptDirectory.from_options(opts)
- script.generate_rev(util.rev_id(), opts.cmd_line_options.message)
+ script = ScriptDirectory.from_config(config)
+ script.generate_rev(util.rev_id(), message)
-def upgrade(opts):
+def upgrade(config):
"""Upgrade to the latest version."""
- script = ScriptDirectory.from_options(opts)
+ script = ScriptDirectory.from_config(config)
# ...
-def revert(opts):
+def revert(config):
"""Revert to a specific previous version."""
- script = ScriptDirectory.from_options(opts)
+ script = ScriptDirectory.from_config(config)
# ...
-def history(opts):
+def history(config):
"""List changeset scripts in chronological order."""
- script = ScriptDirectory.from_options(opts)
+ script = ScriptDirectory.from_config(config)
-def splice(opts):
+def splice(config):
"""'splice' two branches, creating a new revision file."""
-def branches(opts):
+def branches(config):
"""Show current un-spliced branch points""" \ No newline at end of file
diff --git a/alembic/config.py b/alembic/config.py
new file mode 100644
index 0000000..b56fc9d
--- /dev/null
+++ b/alembic/config.py
@@ -0,0 +1,34 @@
+import ConfigParser
+import inspect
+import os
+import sys
+from alembic import util
+
+class Config(object):
+ def __init__(self, file_):
+ self.config_file_name = file_
+
+ @util.memoized_property
+ def file_config(self):
+ file_config = ConfigParser.ConfigParser()
+ file_config.read([self.config_file_name])
+ return file_config
+
+ def get_template_directory(self):
+ # TODO: what's the official way to get at
+ # setuptools-installed datafiles ?
+ return os.path.join(os.path.dirname(__file__), '..', 'templates')
+
+ def get_section(self, name):
+ return dict(self.file_config.items(name))
+
+ def get_main_option(self, name, default=None):
+ if not self.file_config.has_section('alembic'):
+ util.err("No config file %r found, or file has no "
+ "'[alembic]' section" % self.config_file_name)
+ if self.file_config.get('alembic', name):
+ return self.file_config.get('alembic', name)
+ else:
+ return default
+
+ \ No newline at end of file
diff --git a/alembic/options.py b/alembic/options.py
deleted file mode 100644
index f54a1b4..0000000
--- a/alembic/options.py
+++ /dev/null
@@ -1,91 +0,0 @@
-from optparse import OptionParser
-import ConfigParser
-import inspect
-import os
-import sys
-from alembic import util
-
-def get_option_parser():
- from alembic import command
-
- # TODO:
- # OK, what's the super option parser library that
- # allows <command> plus command-specfic sub-options ?
- # we're inventing here a bit.
-
- commands = [
- (fn.__name__.replace('_', '-'), fn.__doc__) for fn in
- [getattr(command, name) for name in sorted(dir(command))]
- if inspect.isfunction(fn) and
- fn.__name__[0] != '_' and
- fn.__module__ == 'alembic.command'
- ]
-
- parser = OptionParser(
- "usage: %prog [options] <command> [command arguments]\n\n"
- "Available Commands:\n" +
- "\n".join([
- util.format_opt(cmd, hlp)
- for cmd, hlp in commands
- ])
- )
- parser.add_option("-c", "--config",
- type="string",
- default="alembic.ini",
- help="Alternate config file")
- parser.add_option("-t", "--template",
- default='generic',
- type="string",
- help="Setup template for use with 'init'")
- parser.add_option("-m", "--message",
- type="string",
- help="Message string to use with 'revision'")
- return parser
-
-class Options(object):
- def __init__(self, parser, argv):
- self.parser = parser
- self.cmd_line_options, \
- self.cmd_line_args = parser.parse_args(argv[1:])
- if len(self.cmd_line_args) < 1:
- self.err("no command specified")
-
- @util.memoized_property
- def file_config(self):
- self.config_file_name = self.cmd_line_options.config
- file_config = ConfigParser.ConfigParser()
- file_config.read([self.config_file_name])
- return file_config
-
- def get_command(self):
- return self.cmd_line_args[0]
-
- def get_command_args(self, count, err):
- if len(self.cmd_line_args[1:]) != count:
- self.err(
- "Command %r syntax: %r" %
- (self.get_command(), err))
- return self.cmd_line_args[1:]
-
- def get_template_directory(self):
- # TODO: what's the official way to get at
- # setuptools-installed datafiles ?
- return os.path.join(os.path.dirname(__file__), '..', 'templates')
-
- def get_section(self, name):
- return dict(self.file_config.items(name))
-
- def err(self, msg):
- util.msg(msg)
- sys.exit(-1)
-
- def get_main_option(self, name, default=None):
- if not self.file_config.has_section('alembic'):
- self.err("No config file %r found, or file has no "
- "'[alembic]' section" % self.config_file_name)
- if self.file_config.get('alembic', name):
- return self.file_config.get('alembic', name)
- else:
- return default
-
- \ No newline at end of file
diff --git a/alembic/script.py b/alembic/script.py
index b2fded6..d35751b 100644
--- a/alembic/script.py
+++ b/alembic/script.py
@@ -8,21 +8,19 @@ _rev_file = re.compile(r'([a-z0-9]+)\.py$')
_mod_def_re = re.compile(r'(upgrade|downgrade)_([a-z0-9]+)')
class ScriptDirectory(object):
- def __init__(self, dir, options):
+ def __init__(self, dir):
self.dir = dir
self.versions = os.path.join(self.dir, 'versions')
if not os.access(dir, os.F_OK):
- options.err("Path doesn't exist: %r. Please use "
+ util.err("Path doesn't exist: %r. Please use "
"the 'init' command to create a new "
"scripts folder." % dir)
- self.options = options
@classmethod
- def from_options(cls, options):
+ def from_config(cls, options):
return ScriptDirectory(
- options.get_main_option('script_location'),
- options)
+ options.get_main_option('script_location'))
@util.memoized_property
def _revision_map(self):
diff --git a/alembic/util.py b/alembic/util.py
index 79b1e3b..3e29704 100644
--- a/alembic/util.py
+++ b/alembic/util.py
@@ -39,6 +39,11 @@ def status(_statmsg, fn, *arg, **kw):
sys.stdout.write("FAILED\n")
raise
+def err(message):
+ msg(message)
+ sys.exit(-1)
+
+
def warn(msg):
warnings.warn(msg)
diff --git a/tests/__init__.py b/tests/__init__.py
index 85f79d2..40e7441 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -19,29 +19,18 @@ def assert_compiled(element, assert_string, dialect=None):
dialect = _get_dialect(dialect)
eq_(unicode(element.compile(dialect=dialect)), assert_string)
-def _testing_options(**kw):
- from alembic.options import Options, get_option_parser
+def _testing_config(**kw):
+ from alembic.config import Config
if not os.access(staging_directory, os.F_OK):
os.mkdir(staging_directory)
- kw.setdefault(
- 'config',
- os.path.join(staging_directory, 'test_alembic.ini')
- )
-
- return Options(
- get_option_parser(),
- ["./scripts/alembic"] + \
- list(itertools.chain(*[["--%s" % k, "%s" % v] for k, v in kw.items()])) + \
- ["init"] +\
- [os.path.join(staging_directory, 'scripts')]
- )
+ return Config(os.path.join(staging_directory, 'test_alembic.ini'))
def staging_env(create=True):
from alembic import command, script
- opt = _testing_options()
+ cfg = _testing_config()
if create:
- command.init(opt)
- return script.ScriptDirectory.from_options(opt)
+ command.init(cfg, os.path.join(staging_directory, 'scripts'))
+ return script.ScriptDirectory.from_config(cfg)
def clear_staging_env():
shutil.rmtree(staging_directory, True)