]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- pushed the whole command line options thing into a single main() function
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 28 Apr 2010 19:47:51 +0000 (15:47 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 28 Apr 2010 19:47:51 +0000 (15:47 -0400)
- 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()

alembic/__init__.py
alembic/command.py
alembic/config.py [new file with mode: 0644]
alembic/options.py [deleted file]
alembic/script.py
alembic/util.py
tests/__init__.py

index 649da28b527bae710368f42035fcf501f4602caa..568b0006e5d82ac60390bfdb589271685b854255 100644 (file)
@@ -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)
 
 
 
index 50452b0a8ac5d058eb9cf54d14276e4805af558d..73e1db860bac2ce1e8538da0f04ce2c9ed2e7e00 100644 (file)
@@ -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 (file)
index 0000000..b56fc9d
--- /dev/null
@@ -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 (file)
index f54a1b4..0000000
+++ /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
index b2fded67d3d064f16e9a843f3131271693663ee6..d35751b73fdf6fe2202e4cc7c4819623d856589f 100644 (file)
@@ -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):
index 79b1e3b4542798a4b944698bb3bbd39fe81f4236..3e297043fcd06580d017c846aa934ba8ac24cf8f 100644 (file)
@@ -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)
     
index 85f79d2aec4365134bad426da9318ce6e5f8799b..40e74418ce17ee5f5e3994194b389b42c78777ee 100644 (file)
@@ -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)