summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2007-08-16 14:34:01 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2007-08-16 14:34:01 +0000
commit83f5f700b0a3ac885042a7f1e68f4e7616d1485e (patch)
tree13884e4a182a2b056aeab4e55b05a9cf34f4bc01
parentc568792e81c7a09e3160548e7b8dcb89e9a5fa99 (diff)
Improved error handling for management.py commands, especially for no argument or non-applabel argument commands.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5903 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/core/management/base.py112
-rw-r--r--django/core/management/commands/createcachetable.py7
-rw-r--r--django/core/management/commands/dbshell.py6
-rw-r--r--django/core/management/commands/diffsettings.py6
-rw-r--r--django/core/management/commands/flush.py6
-rw-r--r--django/core/management/commands/inspectdb.py6
-rw-r--r--django/core/management/commands/runserver.py4
-rw-r--r--django/core/management/commands/shell.py6
-rw-r--r--django/core/management/commands/sqlflush.py6
-rw-r--r--django/core/management/commands/startapp.py13
-rw-r--r--django/core/management/commands/startproject.py9
-rw-r--r--django/core/management/commands/syncdb.py8
-rw-r--r--django/core/management/commands/validate.py6
13 files changed, 116 insertions, 79 deletions
diff --git a/django/core/management/base.py b/django/core/management/base.py
index b0a9de5b86..4041787bc3 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -65,6 +65,7 @@ class BaseCommand(object):
def handle(self, *args, **options):
raise NotImplementedError()
+
class AppCommand(BaseCommand):
args = '[appname ...]'
@@ -86,46 +87,77 @@ class AppCommand(BaseCommand):
def handle_app(self, app, **options):
raise NotImplementedError()
-class CopyFilesCommand(BaseCommand):
- requires_model_validation = False
- def copy_helper(self, app_or_project, name, directory, other_name=''):
- import django
- import os
- import re
- import shutil
- other = {'project': 'app', 'app': 'project'}[app_or_project]
- if not re.search(r'^\w+$', name): # If it's not a valid directory name.
- raise CommandError("%r is not a valid %s name. Please use only numbers, letters and underscores." % (name, app_or_project))
- top_dir = os.path.join(directory, name)
- try:
- os.mkdir(top_dir)
- except OSError, e:
- raise CommandError(e)
+class LabelCommand(BaseCommand):
+ args = '[label ...]'
+ label = 'label'
+
+ def handle(self, *labels, **options):
+ if not labels:
+ raise CommandError('Enter at least one %s.' % self.label)
+
+ output = []
+ for label in labels:
+ label_output = self.handle_label(label, **options)
+ if label_output:
+ output.append(label_output)
+ return '\n'.join(output)
+
+ def handle_label(self, label, **options):
+ raise NotImplementedError()
+
+
+class NoArgsCommand(BaseCommand):
+ args = ''
+
+ def handle(self, *args, **options):
+ from django.db import models
+ if len(args) != 0:
+ raise CommandError("Command doesn't accept any arguments")
+
+ return self.handle_noargs(**options)
+
+ def handle_noargs(self, **options):
+ raise NotImplementedError()
+
+
+def copy_helper(app_or_project, name, directory, other_name=''):
+ import django
+ import os
+ import re
+ import shutil
+ other = {'project': 'app', 'app': 'project'}[app_or_project]
+ if not re.search(r'^\w+$', name): # If it's not a valid directory name.
+ raise CommandError("%r is not a valid %s name. Please use only numbers, letters and underscores." % (name, app_or_project))
+ top_dir = os.path.join(directory, name)
+ try:
+ os.mkdir(top_dir)
+ except OSError, e:
+ raise CommandError(e)
- # Determine where the app or project templates are. Use
- # django.__path__[0] because we don't know into which directory
- # django has been installed.
- template_dir = os.path.join(django.__path__[0], 'conf', '%s_template' % app_or_project)
+ # Determine where the app or project templates are. Use
+ # django.__path__[0] because we don't know into which directory
+ # django has been installed.
+ template_dir = os.path.join(django.__path__[0], 'conf', '%s_template' % app_or_project)
- for d, subdirs, files in os.walk(template_dir):
- relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name)
- if relative_dir:
- os.mkdir(os.path.join(top_dir, relative_dir))
- for i, subdir in enumerate(subdirs):
- if subdir.startswith('.'):
- del subdirs[i]
- for f in files:
- if f.endswith('.pyc'):
- continue
- path_old = os.path.join(d, f)
- path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name))
- fp_old = open(path_old, 'r')
- fp_new = open(path_new, 'w')
- fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name))
- fp_old.close()
- fp_new.close()
- try:
- shutil.copymode(path_old, path_new)
- except OSError:
- 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))
+ for d, subdirs, files in os.walk(template_dir):
+ relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name)
+ if relative_dir:
+ os.mkdir(os.path.join(top_dir, relative_dir))
+ for i, subdir in enumerate(subdirs):
+ if subdir.startswith('.'):
+ del subdirs[i]
+ for f in files:
+ if f.endswith('.pyc'):
+ continue
+ path_old = os.path.join(d, f)
+ path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name))
+ fp_old = open(path_old, 'r')
+ fp_new = open(path_new, 'w')
+ fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name))
+ fp_old.close()
+ fp_new.close()
+ try:
+ shutil.copymode(path_old, path_new)
+ except OSError:
+ 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))
diff --git a/django/core/management/commands/createcachetable.py b/django/core/management/commands/createcachetable.py
index df1812174a..dc8b1b7854 100644
--- a/django/core/management/commands/createcachetable.py
+++ b/django/core/management/commands/createcachetable.py
@@ -1,12 +1,13 @@
-from django.core.management.base import BaseCommand
+from django.core.management.base import LabelCommand
-class Command(BaseCommand):
+class Command(LabelCommand):
help = "Creates the table needed to use the SQL cache backend."
args = "[tablename]"
+ label = 'tablename'
requires_model_validation = False
- def handle(self, tablename, **options):
+ def handle_label(self, tablename, **options):
from django.db import backend, connection, transaction, models
fields = (
# "key" is a reserved word in MySQL, so use "cache_key" instead.
diff --git a/django/core/management/commands/dbshell.py b/django/core/management/commands/dbshell.py
index 401ed847b0..ec2a961530 100644
--- a/django/core/management/commands/dbshell.py
+++ b/django/core/management/commands/dbshell.py
@@ -1,10 +1,10 @@
-from django.core.management.base import BaseCommand
+from django.core.management.base import NoArgsCommand
-class Command(BaseCommand):
+class Command(NoArgsCommand):
help = "Runs the command-line client for the current DATABASE_ENGINE."
requires_model_validation = False
- def handle(self, **options):
+ def handle_noargs(self, **options):
from django.db import runshell
runshell()
diff --git a/django/core/management/commands/diffsettings.py b/django/core/management/commands/diffsettings.py
index a51bddc477..2459f11700 100644
--- a/django/core/management/commands/diffsettings.py
+++ b/django/core/management/commands/diffsettings.py
@@ -1,17 +1,17 @@
-from django.core.management.base import BaseCommand
+from django.core.management.base import NoArgsCommand
def module_to_dict(module, omittable=lambda k: k.startswith('_')):
"Converts a module namespace to a Python dictionary. Used by get_settings_diff."
return dict([(k, repr(v)) for k, v in module.__dict__.items() if not omittable(k)])
-class Command(BaseCommand):
+class Command(NoArgsCommand):
help = """Displays differences between the current settings.py and Django's
default settings. Settings that don't appear in the defaults are
followed by "###"."""
requires_model_validation = False
- def handle(self, **options):
+ def handle_noargs(self, **options):
# Inspired by Postfix's "postconf -n".
from django.conf import settings, global_settings
diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py
index c6e902b946..bd1dc204d2 100644
--- a/django/core/management/commands/flush.py
+++ b/django/core/management/commands/flush.py
@@ -1,11 +1,11 @@
-from django.core.management.base import BaseCommand, CommandError
+from django.core.management.base import NoArgsCommand, CommandError
from django.core.management.color import no_style
-class Command(BaseCommand):
+class Command(NoArgsCommand):
help = "Executes ``sqlflush`` on the current database."
args = '[--verbosity] [--noinput]'
- def handle(self, **options):
+ def handle_noargs(self, **options):
from django.conf import settings
from django.db import connection, transaction, models
from django.dispatch import dispatcher
diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py
index 6f28b6f980..11bc390289 100644
--- a/django/core/management/commands/inspectdb.py
+++ b/django/core/management/commands/inspectdb.py
@@ -1,11 +1,11 @@
-from django.core.management.base import BaseCommand, CommandError
+from django.core.management.base import NoArgsCommand, CommandError
-class Command(BaseCommand):
+class Command(NoArgsCommand):
help = "Introspects the database tables in the given database and outputs a Django model module."
requires_model_validation = False
- def handle(self, **options):
+ def handle_noargs(self, **options):
try:
for line in self.handle_inspection():
print line
diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
index cdab46c5a0..d34a25f3e2 100644
--- a/django/core/management/commands/runserver.py
+++ b/django/core/management/commands/runserver.py
@@ -9,10 +9,12 @@ class Command(BaseCommand):
# Validation is called explicitly each time the server is reloaded.
requires_model_validation = False
- def handle(self, addrport='', **options):
+ def handle(self, addrport='', *args, **options):
import django
from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException
from django.core.handlers.wsgi import WSGIHandler
+ if len(args) != 0:
+ raise CommandError('Usage is runserver %s' % self.args)
if not addrport:
addr = ''
port = '8000'
diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py
index 68f8c7b4e5..bc76c44b97 100644
--- a/django/core/management/commands/shell.py
+++ b/django/core/management/commands/shell.py
@@ -1,12 +1,12 @@
-from django.core.management.base import BaseCommand
+from django.core.management.base import NoArgsCommand
-class Command(BaseCommand):
+class Command(NoArgsCommand):
help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available."
args = '[--plain]'
requires_model_validation = False
- def handle(self, **options):
+ def handle_noargs(self, **options):
# XXX: (Temporary) workaround for ticket #1796: force early loading of all
# models from installed apps.
from django.db.models.loading import get_models
diff --git a/django/core/management/commands/sqlflush.py b/django/core/management/commands/sqlflush.py
index ff6a9cceea..7d14fe61e1 100644
--- a/django/core/management/commands/sqlflush.py
+++ b/django/core/management/commands/sqlflush.py
@@ -1,10 +1,10 @@
-from django.core.management.base import BaseCommand
+from django.core.management.base import NoArgsCommand
-class Command(BaseCommand):
+class Command(NoArgsCommand):
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."
output_transaction = True
- def handle(self, **options):
+ def handle_noargs(self, **options):
from django.core.management.sql import sql_flush
return '\n'.join(sql_flush(self.style))
diff --git a/django/core/management/commands/startapp.py b/django/core/management/commands/startapp.py
index ae37afc11e..acc965cf44 100644
--- a/django/core/management/commands/startapp.py
+++ b/django/core/management/commands/startapp.py
@@ -1,16 +1,17 @@
-from django.core.management.base import CopyFilesCommand, CommandError
+from django.core.management.base import copy_helper, CommandError, LabelCommand
import os
-class Command(CopyFilesCommand):
+class Command(LabelCommand):
help = "Creates a Django app directory structure for the given app name in the current directory."
args = "[appname]"
+ label = 'application name'
requires_model_validation = False
# Can't import settings during this command, because they haven't
# necessarily been created.
can_import_settings = False
- def handle(self, app_name, directory=None, **options):
+ def handle_label(self, app_name, directory=None, **options):
if directory is None:
directory = os.getcwd()
# Determine the project_name a bit naively -- by looking at the name of
@@ -20,7 +21,7 @@ class Command(CopyFilesCommand):
project_name = os.path.basename(directory)
if app_name == project_name:
raise CommandError("You cannot create an app with the same name (%r) as your project." % app_name)
- self.copy_helper('app', app_name, directory, parent_dir)
+ copy_helper('app', app_name, directory, parent_dir)
class ProjectCommand(Command):
help = "Creates a Django app directory structure for the given app name in this project's directory."
@@ -29,5 +30,5 @@ class ProjectCommand(Command):
super(ProjectCommand, self).__init__()
self.project_directory = project_directory
- def handle(self, app_name, **options):
- super(ProjectCommand, self).handle(app_name, self.project_directory, **options)
+ def handle_label(self, app_name, **options):
+ super(ProjectCommand, self).handle_label(app_name, self.project_directory, **options)
diff --git a/django/core/management/commands/startproject.py b/django/core/management/commands/startproject.py
index 5be4edd9ad..8394117b70 100644
--- a/django/core/management/commands/startproject.py
+++ b/django/core/management/commands/startproject.py
@@ -1,20 +1,21 @@
-from django.core.management.base import CopyFilesCommand, CommandError
+from django.core.management.base import copy_helper, CommandError, LabelCommand
import os
import re
from random import choice
INVALID_PROJECT_NAMES = ('django', 'site', 'test')
-class Command(CopyFilesCommand):
+class Command(LabelCommand):
help = "Creates a Django project directory structure for the given project name in the current directory."
args = "[projectname]"
+ label = 'project name'
requires_model_validation = False
# Can't import settings during this command, because they haven't
# necessarily been created.
can_import_settings = False
- def handle(self, project_name, **options):
+ def handle_label(self, project_name, **options):
# Determine the project_name a bit naively -- by looking at the name of
# the parent directory.
directory = os.getcwd()
@@ -22,7 +23,7 @@ class Command(CopyFilesCommand):
if project_name in INVALID_PROJECT_NAMES:
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)
- self.copy_helper('project', project_name, directory)
+ copy_helper('project', project_name, directory)
# Create a random SECRET_KEY hash, and put it in the main settings.
main_settings_file = os.path.join(directory, project_name, 'settings.py')
diff --git a/django/core/management/commands/syncdb.py b/django/core/management/commands/syncdb.py
index b388b41043..d87b0d38d9 100644
--- a/django/core/management/commands/syncdb.py
+++ b/django/core/management/commands/syncdb.py
@@ -1,4 +1,4 @@
-from django.core.management.base import BaseCommand
+from django.core.management.base import NoArgsCommand
from django.core.management.color import no_style
try:
@@ -6,15 +6,15 @@ try:
except NameError:
from sets import Set as set # Python 2.3 fallback
-class Command(BaseCommand):
+class Command(NoArgsCommand):
help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
args = '[--verbosity] [--noinput]'
- def handle(self, **options):
+ def handle_noargs(self, **options):
from django.db import backend, connection, transaction, models
from django.conf import settings
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
-
+
verbosity = int(options.get('verbosity', 1))
interactive = options.get('interactive')
diff --git a/django/core/management/commands/validate.py b/django/core/management/commands/validate.py
index 77d414acd8..2751f41abd 100644
--- a/django/core/management/commands/validate.py
+++ b/django/core/management/commands/validate.py
@@ -1,9 +1,9 @@
-from django.core.management.base import BaseCommand
+from django.core.management.base import NoArgsCommand
-class Command(BaseCommand):
+class Command(NoArgsCommand):
help = "Validates all installed models."
requires_model_validation = False
- def handle(self, **options):
+ def handle_noargs(self, **options):
self.validate()