Django

Code

Changeset 5903

Show
Ignore:
Timestamp:
08/16/07 09:34:01 (1 year ago)
Author:
russellm
Message:

Improved error handling for management.py commands, especially for no argument or non-applabel argument commands.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/core/management/base.py

    r5898 r5903  
    6666        raise NotImplementedError() 
    6767 
     68 
    6869class AppCommand(BaseCommand): 
    6970    args = '[appname ...]' 
     
    8788        raise NotImplementedError() 
    8889 
    89 class CopyFilesCommand(BaseCommand): 
    90     requires_model_validation = False 
    9190 
    92     def copy_helper(self, app_or_project, name, directory, other_name=''): 
    93         import django 
    94         import os 
    95         import re 
    96         import shutil 
    97         other = {'project': 'app', 'app': 'project'}[app_or_project] 
    98         if not re.search(r'^\w+$', name): # If it's not a valid directory name. 
    99             raise CommandError("%r is not a valid %s name. Please use only numbers, letters and underscores." % (name, app_or_project)) 
    100         top_dir = os.path.join(directory, name) 
    101         try: 
    102             os.mkdir(top_dir) 
    103         except OSError, e: 
    104             raise CommandError(e) 
     91class LabelCommand(BaseCommand): 
     92    args = '[label ...]' 
     93    label = 'label' 
     94     
     95    def handle(self, *labels, **options): 
     96        if not labels: 
     97            raise CommandError('Enter at least one %s.' % self.label) 
    10598 
    106         # Determine where the app or project templates are. Use 
    107         # django.__path__[0] because we don't know into which directory 
    108         # django has been installed. 
    109         template_dir = os.path.join(django.__path__[0], 'conf', '%s_template' % app_or_project) 
     99        output = [] 
     100        for label in labels: 
     101            label_output = self.handle_label(label, **options) 
     102            if label_output: 
     103                output.append(label_output) 
     104        return '\n'.join(output) 
    110105 
    111         for d, subdirs, files in os.walk(template_dir): 
    112             relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name) 
    113             if relative_dir: 
    114                 os.mkdir(os.path.join(top_dir, relative_dir)) 
    115             for i, subdir in enumerate(subdirs): 
    116                 if subdir.startswith('.'): 
    117                     del subdirs[i] 
    118             for f in files: 
    119                 if f.endswith('.pyc'): 
    120                     continue 
    121                 path_old = os.path.join(d, f) 
    122                 path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name)) 
    123                 fp_old = open(path_old, 'r') 
    124                 fp_new = open(path_new, 'w') 
    125                 fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name)) 
    126                 fp_old.close() 
    127                 fp_new.close() 
    128                 try: 
    129                     shutil.copymode(path_old, path_new) 
    130                 except OSError: 
    131                     sys.stderr.write(self.style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new)) 
     106    def handle_label(self, label, **options): 
     107        raise NotImplementedError() 
     108 
     109 
     110class NoArgsCommand(BaseCommand): 
     111    args = '' 
     112 
     113    def handle(self, *args, **options): 
     114        from django.db import models 
     115        if len(args) != 0: 
     116            raise CommandError("Command doesn't accept any arguments") 
     117 
     118        return self.handle_noargs(**options) 
     119 
     120    def handle_noargs(self, **options): 
     121        raise NotImplementedError() 
     122 
     123     
     124def copy_helper(app_or_project, name, directory, other_name=''): 
     125    import django 
     126    import os 
     127    import re 
     128    import shutil 
     129    other = {'project': 'app', 'app': 'project'}[app_or_project] 
     130    if not re.search(r'^\w+$', name): # If it's not a valid directory name. 
     131        raise CommandError("%r is not a valid %s name. Please use only numbers, letters and underscores." % (name, app_or_project)) 
     132    top_dir = os.path.join(directory, name) 
     133    try: 
     134        os.mkdir(top_dir) 
     135    except OSError, e: 
     136        raise CommandError(e) 
     137 
     138    # Determine where the app or project templates are. Use 
     139    # django.__path__[0] because we don't know into which directory 
     140    # django has been installed. 
     141    template_dir = os.path.join(django.__path__[0], 'conf', '%s_template' % app_or_project) 
     142 
     143    for d, subdirs, files in os.walk(template_dir): 
     144        relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name) 
     145        if relative_dir: 
     146            os.mkdir(os.path.join(top_dir, relative_dir)) 
     147        for i, subdir in enumerate(subdirs): 
     148            if subdir.startswith('.'): 
     149                del subdirs[i] 
     150        for f in files: 
     151            if f.endswith('.pyc'): 
     152                continue 
     153            path_old = os.path.join(d, f) 
     154            path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name)) 
     155            fp_old = open(path_old, 'r') 
     156            fp_new = open(path_new, 'w') 
     157            fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name)) 
     158            fp_old.close() 
     159            fp_new.close() 
     160            try: 
     161                shutil.copymode(path_old, path_new) 
     162            except OSError: 
     163                sys.stderr.write(self.style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new)) 
  • django/trunk/django/core/management/commands/createcachetable.py

    r5898 r5903  
    1 from django.core.management.base import BaseCommand 
     1from django.core.management.base import LabelCommand 
    22 
    3 class Command(BaseCommand): 
     3class Command(LabelCommand): 
    44    help = "Creates the table needed to use the SQL cache backend." 
    55    args = "[tablename]" 
     6    label = 'tablename' 
    67 
    78    requires_model_validation = False 
    89 
    9     def handle(self, tablename, **options): 
     10    def handle_label(self, tablename, **options): 
    1011        from django.db import backend, connection, transaction, models 
    1112        fields = ( 
  • django/trunk/django/core/management/commands/dbshell.py

    r5898 r5903  
    1 from django.core.management.base import BaseCommand 
     1from django.core.management.base import NoArgsCommand 
    22 
    3 class Command(BaseCommand): 
     3class Command(NoArgsCommand): 
    44    help = "Runs the command-line client for the current DATABASE_ENGINE." 
    55 
    66    requires_model_validation = False 
    77 
    8     def handle(self, **options): 
     8    def handle_noargs(self, **options): 
    99        from django.db import runshell 
    1010        runshell() 
  • django/trunk/django/core/management/commands/diffsettings.py

    r5898 r5903  
    1 from django.core.management.base import BaseCommand 
     1from django.core.management.base import NoArgsCommand 
    22 
    33def module_to_dict(module, omittable=lambda k: k.startswith('_')): 
     
    55    return dict([(k, repr(v)) for k, v in module.__dict__.items() if not omittable(k)]) 
    66 
    7 class Command(BaseCommand): 
     7class Command(NoArgsCommand): 
    88    help = """Displays differences between the current settings.py and Django's 
    99    default settings. Settings that don't appear in the defaults are 
     
    1212    requires_model_validation = False 
    1313 
    14     def handle(self, **options): 
     14    def handle_noargs(self, **options): 
    1515        # Inspired by Postfix's "postconf -n". 
    1616        from django.conf import settings, global_settings 
  • django/trunk/django/core/management/commands/flush.py

    r5898 r5903  
    1 from django.core.management.base import BaseCommand, CommandError 
     1from django.core.management.base import NoArgsCommand, CommandError 
    22from django.core.management.color import no_style 
    33 
    4 class Command(BaseCommand): 
     4class Command(NoArgsCommand): 
    55    help = "Executes ``sqlflush`` on the current database." 
    66    args = '[--verbosity] [--noinput]' 
    77 
    8     def handle(self, **options): 
     8    def handle_noargs(self, **options): 
    99        from django.conf import settings 
    1010        from django.db import connection, transaction, models 
  • django/trunk/django/core/management/commands/inspectdb.py

    r5898 r5903  
    1 from django.core.management.base import BaseCommand, CommandError 
     1from django.core.management.base import NoArgsCommand, CommandError 
    22 
    3 class Command(BaseCommand): 
     3class Command(NoArgsCommand): 
    44    help = "Introspects the database tables in the given database and outputs a Django model module." 
    55 
    66    requires_model_validation = False 
    77 
    8     def handle(self, **options): 
     8    def handle_noargs(self, **options): 
    99        try: 
    1010            for line in self.handle_inspection(): 
  • django/trunk/django/core/management/commands/runserver.py

    r5898 r5903  
    1010    requires_model_validation = False 
    1111 
    12     def handle(self, addrport='', **options): 
     12    def handle(self, addrport='', *args, **options): 
    1313        import django 
    1414        from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException 
    1515        from django.core.handlers.wsgi import WSGIHandler 
     16        if len(args) != 0: 
     17            raise CommandError('Usage is runserver %s' % self.args) 
    1618        if not addrport: 
    1719            addr = '' 
  • django/trunk/django/core/management/commands/shell.py

    r5898 r5903  
    1 from django.core.management.base import BaseCommand 
     1from django.core.management.base import NoArgsCommand 
    22 
    3 class Command(BaseCommand): 
     3class Command(NoArgsCommand): 
    44    help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available." 
    55    args = '[--plain]' 
     
    77    requires_model_validation = False 
    88 
    9     def handle(self, **options): 
     9    def handle_noargs(self, **options): 
    1010        # XXX: (Temporary) workaround for ticket #1796: force early loading of all 
    1111        # models from installed apps. 
  • django/trunk/django/core/management/commands/sqlflush.py

    r5898 r5903  
    1 from django.core.management.base import BaseCommand 
     1from django.core.management.base import NoArgsCommand 
    22 
    3 class Command(BaseCommand): 
     3class Command(NoArgsCommand): 
    44    help = "Returns a list of the SQL statements required to return all tables in the database to the state they were in just after they were installed." 
    55 
    66    output_transaction = True 
    77 
    8     def handle(self, **options): 
     8    def handle_noargs(self, **options): 
    99        from django.core.management.sql import sql_flush 
    1010        return '\n'.join(sql_flush(self.style)) 
  • django/trunk/django/core/management/commands/startapp.py

    r5901 r5903  
    1 from django.core.management.base import CopyFilesCommand, CommandError 
     1from django.core.management.base import copy_helper, CommandError, LabelCommand 
    22import os 
    33 
    4 class Command(CopyFilesCommand): 
     4class Command(LabelCommand): 
    55    help = "Creates a Django app directory structure for the given app name in the current directory." 
    66    args = "[appname]" 
     7    label = 'application name' 
    78 
    89    requires_model_validation = False 
     
    1112    can_import_settings = False 
    1213 
    13     def handle(self, app_name, directory=None, **options): 
     14    def handle_label(self, app_name, directory=None, **options): 
    1415        if directory is None: 
    1516            directory = os.getcwd() 
     
    2122        if app_name == project_name: 
    2223            raise CommandError("You cannot create an app with the same name (%r) as your project." % app_name) 
    23         self.copy_helper('app', app_name, directory, parent_dir) 
     24        copy_helper('app', app_name, directory, parent_dir) 
    2425 
    2526class ProjectCommand(Command): 
     
    3031        self.project_directory = project_directory 
    3132 
    32     def handle(self, app_name, **options): 
    33         super(ProjectCommand, self).handle(app_name, self.project_directory, **options) 
     33    def handle_label(self, app_name, **options): 
     34        super(ProjectCommand, self).handle_label(app_name, self.project_directory, **options) 
  • django/trunk/django/core/management/commands/startproject.py

    r5898 r5903  
    1 from django.core.management.base import CopyFilesCommand, CommandError 
     1from django.core.management.base import copy_helper, CommandError, LabelCommand 
    22import os 
    33import re 
     
    66INVALID_PROJECT_NAMES = ('django', 'site', 'test') 
    77 
    8 class Command(CopyFilesCommand): 
     8class Command(LabelCommand): 
    99    help = "Creates a Django project directory structure for the given project name in the current directory." 
    1010    args = "[projectname]" 
     11    label = 'project name' 
    1112 
    1213    requires_model_validation = False 
     
    1516    can_import_settings = False 
    1617 
    17     def handle(self, project_name, **options): 
     18    def handle_label(self, project_name, **options): 
    1819        # Determine the project_name a bit naively -- by looking at the name of 
    1920        # the parent directory. 
     
    2324            raise CommandError("%r conflicts with the name of an existing Python module and cannot be used as a project name. Please try another name." % project_name) 
    2425 
    25         self.copy_helper('project', project_name, directory) 
     26        copy_helper('project', project_name, directory) 
    2627 
    2728        # Create a random SECRET_KEY hash, and put it in the main settings. 
  • django/trunk/django/core/management/commands/syncdb.py

    r5898 r5903  
    1 from django.core.management.base import BaseCommand 
     1from django.core.management.base import NoArgsCommand 
    22from django.core.management.color import no_style 
    33 
     
    77    from sets import Set as set   # Python 2.3 fallback 
    88 
    9 class Command(BaseCommand): 
     9class Command(NoArgsCommand): 
    1010    help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created." 
    1111    args = '[--verbosity] [--noinput]' 
    1212 
    13     def handle(self, **options): 
     13    def handle_noargs(self, **options): 
    1414        from django.db import backend, connection, transaction, models 
    1515        from django.conf import settings 
    1616        from django.core.management.sql import table_list, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal 
    17  
     17             
    1818        verbosity = int(options.get('verbosity', 1)) 
    1919        interactive = options.get('interactive') 
  • django/trunk/django/core/management/commands/validate.py

    r5898 r5903  
    1 from django.core.management.base import BaseCommand 
     1from django.core.management.base import NoArgsCommand 
    22 
    3 class Command(BaseCommand): 
     3class Command(NoArgsCommand): 
    44    help = "Validates all installed models." 
    55 
    66    requires_model_validation = False 
    77 
    8     def handle(self, **options): 
     8    def handle_noargs(self, **options): 
    99        self.validate()