Skip to content

Instantly share code, notes, and snippets.

@genomics-geek
Forked from bruth/README.md
Created April 15, 2017 02:46
Show Gist options
  • Save genomics-geek/a5026a222e3816dff805d08bc9a29f98 to your computer and use it in GitHub Desktop.
Save genomics-geek/a5026a222e3816dff805d08bc9a29f98 to your computer and use it in GitHub Desktop.

Revisions

  1. @bruth bruth revised this gist Jul 31, 2013. 1 changed file with 0 additions and 6 deletions.
    6 changes: 0 additions & 6 deletions subcommander.py
    Original file line number Diff line number Diff line change
    @@ -4,12 +4,6 @@
    from django.utils.importlib import import_module


    import sys
    from optparse import NO_DEFAULT, OptionParser
    from django.core.management.base import CommandError, BaseCommand, handle_default_options
    from django.utils.importlib import import_module


    class Subcommander(BaseCommand):
    help = "A wrapper for subcommands"

  2. @bruth bruth created this gist Jul 31, 2013.
    30 changes: 30 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,30 @@
    ## Subcommander

    Managment commands are assumed to be unique across all apps in a Django project. This can lead to long or obscure command names in attempt to namespace those commands.

    Subcommander acts as a proxy command giving the _real_ commands a namespace. The subcommander module can be named after the app name or some derivation. The structure looks as follows:

    ```bash
    myapp/
    management/
    commands/
    myapp.py
    subcommands/
    cmd1.py
    cmd2.py
    ...
    ```

    The command defined in each module under `subcommands/` are defined [as normal](https://docs.djangoproject.com/en/1.5/howto/custom-management-commands/). The `commands/myapp.py` should look like the following:

    ```python
    from subcommander import Subcommander

    class Command(Subcommander):
    subcommands = {
    'cmd1': 'cmd1',
    'cmd2': 'cmd2',
    }
    ```

    The `subcommands` dict looks unnecessary, but it enables mapping a cleaner command line name to the command module, e.g. `load` => `load_data`.
    80 changes: 80 additions & 0 deletions subcommander.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    import sys
    from optparse import NO_DEFAULT, OptionParser
    from django.core.management.base import CommandError, BaseCommand, handle_default_options
    from django.utils.importlib import import_module


    import sys
    from optparse import NO_DEFAULT, OptionParser
    from django.core.management.base import CommandError, BaseCommand, handle_default_options
    from django.utils.importlib import import_module


    class Subcommander(BaseCommand):
    help = "A wrapper for subcommands"

    subcommands = {}

    import_template = '{app_name}.management.subcommands.{module_name}'

    def print_subcommands(self, prog_name):
    usage = ['', 'Available subcommands:']
    for name in sorted(self.subcommands):
    usage.append(' {0}'.format(name))
    return '\n'.join(usage)

    def usage(self, subcommand):
    usage = '%prog {0} subcommand [options] [args]'.format(subcommand)
    if self.help:
    return '{0}\n\n{1}'.format(usage, self.help)
    return usage

    def print_help(self, prog_name, subcommand):
    super(Subcommander, self).print_help(prog_name, subcommand)
    sys.stdout.write('{0}\n\n'.format(self.print_subcommands(prog_name)))

    def get_subcommand(self, subcommand):
    try:
    module = import_module(self.import_template.format(app_name=self.app_name,
    module_name=self.subcommands[subcommand]))
    return module.Command()
    except KeyError:
    raise CommandError('Unknown subcommand: {0} {1}'.format(self.app_name, subcommand))

    def run_from_argv(self, argv):
    """Set up any environment changes requested (e.g., Python path
    and Django settings), then run this command.
    """
    if len(argv) > 2 and not argv[2].startswith('-') and argv[2] in self.subcommands.keys():
    subcommand = argv[2]
    klass = self.get_subcommand(subcommand)
    parser = OptionParser(prog=argv[0], usage=klass.usage('{0} {1}'.format(argv[1], subcommand)),
    version=klass.get_version(), option_list=klass.option_list)
    options, args = parser.parse_args(argv[3:])
    args = [subcommand] + args
    else:
    parser = self.create_parser(argv[0], argv[1])
    options, args = parser.parse_args(argv[2:])

    handle_default_options(options)
    self.execute(*args, **options.__dict__)

    def handle(self, *args, **options):
    if not args or args[0] not in self.subcommands.keys():
    return self.print_help('./manage.py', self.app_name)
    subcommand, args = args[0], args[1:]

    klass = self.get_subcommand(subcommand)
    # Grab out a list of defaults from the options. optparse does this for
    # us when the script runs from the command line, but since
    # call_command can be called programatically, we need to simulate the
    # loading and handling of defaults (see #10080 for details).
    defaults = {}
    for opt in klass.option_list:
    if opt.default is NO_DEFAULT:
    defaults[opt.dest] = None
    else:
    defaults[opt.dest] = opt.default
    defaults.update(options)

    return klass.execute(*args, **defaults)