From ec7d8b7c6147397fd689ee9538801bd0df59d73a Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sun, 10 Aug 2008 08:42:49 +0000 Subject: [PATCH] Fixed #5943 -- Modified django-admin to behave like manage.py if settings are provided, either as --settings or DJANGO_SETTINGS_MODULE. Thanks to Joseph Kocherhans and Todd O'Bryan for their work on this ticket. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8282 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/management/__init__.py | 58 ++++++++-------- django/core/management/base.py | 11 ++- tests/regressiontests/admin_scripts/tests.py | 70 ++++++++++---------- 3 files changed, 70 insertions(+), 69 deletions(-) diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py index d689199bc8..74e2b9d211 100644 --- a/django/core/management/__init__.py +++ b/django/core/management/__init__.py @@ -66,7 +66,7 @@ def load_command_class(app_name, name): return getattr(__import__('%s.management.commands.%s' % (app_name, name), {}, {}, ['Command']), 'Command')() -def get_commands(load_user_commands=True, project_directory=None): +def get_commands(): """ Returns a dictionary mapping command names to their callback applications. @@ -77,7 +77,7 @@ def get_commands(load_user_commands=True, project_directory=None): Core commands are always included. If a settings module has been specified, user-defined commands will also be included, the startproject command will be disabled, and the startapp command - will be modified to use the directory in which that module appears. + will be modified to use the directory in which the settings module appears. The dictionary is in the format {command_name: app_name}. Key-value pairs from this dictionary can then be used in calls to @@ -94,15 +94,28 @@ def get_commands(load_user_commands=True, project_directory=None): if _commands is None: _commands = dict([(name, 'django.core') for name in find_commands(__path__[0])]) - if load_user_commands: - # Get commands from all installed apps. + # Find the installed apps + try: from django.conf import settings - for app_name in settings.INSTALLED_APPS: - try: - path = find_management_module(app_name) - _commands.update(dict([(name, app_name) for name in find_commands(path)])) - except ImportError: - pass # No management module -- ignore this app. + apps = settings.INSTALLED_APPS + except (AttributeError, EnvironmentError, ImportError): + apps = [] + + # Find the project directory + try: + from django.conf import settings + project_directory = setup_environ(__import__(settings.SETTINGS_MODULE)) + except (AttributeError, EnvironmentError, ImportError): + project_directory = None + + # Find and load the management module for each installed app. + for app_name in apps: + try: + path = find_management_module(app_name) + _commands.update(dict([(name, app_name) + for name in find_commands(path)])) + except ImportError: + pass # No management module - ignore this app if project_directory: # Remove the "startproject" command from self.commands, because @@ -203,8 +216,6 @@ class ManagementUtility(object): def __init__(self, argv=None): self.argv = argv or sys.argv[:] self.prog_name = os.path.basename(self.argv[0]) - self.project_directory = None - self.user_commands = False def main_help_text(self): """ @@ -212,7 +223,7 @@ class ManagementUtility(object): """ usage = ['',"Type '%s help ' for help on a specific subcommand." % self.prog_name,''] usage.append('Available subcommands:') - commands = get_commands(self.user_commands, self.project_directory).keys() + commands = get_commands().keys() commands.sort() for cmd in commands: usage.append(' %s' % cmd) @@ -225,7 +236,7 @@ class ManagementUtility(object): "django-admin.py" or "manage.py") if it can't be found. """ try: - app_name = get_commands(self.user_commands, self.project_directory)[subcommand] + app_name = get_commands()[subcommand] if isinstance(app_name, BaseCommand): # If the command is already loaded, use it directly. klass = app_name @@ -278,20 +289,6 @@ class ManagementUtility(object): else: self.fetch_command(subcommand).run_from_argv(self.argv) -class ProjectManagementUtility(ManagementUtility): - """ - A ManagementUtility that is specific to a particular Django project. - As such, its commands are slightly different than those of its parent - class. - - In practice, this class represents manage.py, whereas ManagementUtility - represents django-admin.py. - """ - def __init__(self, argv, project_directory): - super(ProjectManagementUtility, self).__init__(argv) - self.project_directory = project_directory - self.user_commands = True - def setup_environ(settings_mod): """ Configures the runtime environment. This can also be used by external @@ -313,7 +310,6 @@ def setup_environ(settings_mod): # Set DJANGO_SETTINGS_MODULE appropriately. os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name) - return project_directory def execute_from_command_line(argv=None): """ @@ -327,6 +323,6 @@ def execute_manager(settings_mod, argv=None): Like execute_from_command_line(), but for use by manage.py, a project-specific django-admin.py utility. """ - project_directory = setup_environ(settings_mod) - utility = ProjectManagementUtility(argv, project_directory) + setup_environ(settings_mod) + utility = ManagementUtility(argv) utility.execute() diff --git a/django/core/management/base.py b/django/core/management/base.py index fb0cff3f3b..20cc7c0f40 100644 --- a/django/core/management/base.py +++ b/django/core/management/base.py @@ -82,9 +82,14 @@ class BaseCommand(object): # But only do this if we can assume we have a working settings file, # because django.utils.translation requires settings. if self.can_import_settings: - from django.utils import translation - translation.activate('en-us') - + try: + from django.utils import translation + translation.activate('en-us') + except ImportError, e: + # If settings should be available, but aren't, + # raise the error and quit. + sys.stderr.write(self.style.ERROR(str('Error: %s\n' % e))) + sys.exit(1) try: if self.requires_model_validation: self.validate() diff --git a/tests/regressiontests/admin_scripts/tests.py b/tests/regressiontests/admin_scripts/tests.py index 98e6582c75..3cbcb1cf92 100644 --- a/tests/regressiontests/admin_scripts/tests.py +++ b/tests/regressiontests/admin_scripts/tests.py @@ -223,25 +223,25 @@ class DjangoAdminDefaultSettings(AdminScriptTestCase): self.assertOutput(err, "Could not import settings 'bad_settings'") def test_custom_command(self): - "default: django-admin can't execute user commands" + "default: django-admin can't execute user commands if it isn't provided settings" args = ['noargs_command'] out, err = self.run_django_admin(args) self.assertNoOutput(out) self.assertOutput(err, "Unknown command: 'noargs_command'") def test_custom_command_with_settings(self): - "default: django-admin can't execute user commands, even if settings are provided as argument" + "default: django-admin can execute user commands if settings are provided as argument" args = ['noargs_command', '--settings=settings'] out, err = self.run_django_admin(args) - self.assertNoOutput(out) - self.assertOutput(err, "Unknown command: 'noargs_command'") + self.assertNoOutput(err) + self.assertOutput(out, "EXECUTE:NoArgsCommand") def test_custom_command_with_environment(self): - "default: django-admin can't execute user commands, even if settings are provided in environment" + "default: django-admin can execute user commands if settings are provided in environment" args = ['noargs_command'] out, err = self.run_django_admin(args,'settings') - self.assertNoOutput(out) - self.assertOutput(err, "Unknown command: 'noargs_command'") + self.assertNoOutput(err) + self.assertOutput(out, "EXECUTE:NoArgsCommand") class DjangoAdminFullPathDefaultSettings(AdminScriptTestCase): """A series of tests for django-admin.py when using a settings.py file that @@ -261,18 +261,18 @@ class DjangoAdminFullPathDefaultSettings(AdminScriptTestCase): self.assertOutput(err, 'environment variable DJANGO_SETTINGS_MODULE is undefined') def test_builtin_with_settings(self): - "fulldefault: django-admin builtin commands fail if user app isn't on path" + "fulldefault: django-admin builtin commands succeed if a settings file is provided" args = ['sqlall','--settings=settings', 'admin_scripts'] out, err = self.run_django_admin(args) - self.assertNoOutput(out) - self.assertOutput(err, 'ImportError: No module named regressiontests') + self.assertNoOutput(err) + self.assertOutput(out, 'CREATE TABLE') def test_builtin_with_environment(self): - "fulldefault: django-admin builtin commands fail if user app isn't on path" + "fulldefault: django-admin builtin commands succeed if the environment contains settings" args = ['sqlall','admin_scripts'] out, err = self.run_django_admin(args,'settings') - self.assertNoOutput(out) - self.assertOutput(err, 'ImportError: No module named regressiontests') + self.assertNoOutput(err) + self.assertOutput(out, 'CREATE TABLE') def test_builtin_with_bad_settings(self): "fulldefault: django-admin builtin commands fail if settings file (from argument) doesn't exist" @@ -289,25 +289,25 @@ class DjangoAdminFullPathDefaultSettings(AdminScriptTestCase): self.assertOutput(err, "Could not import settings 'bad_settings'") def test_custom_command(self): - "fulldefault: django-admin can't execute user commands" + "fulldefault: django-admin can't execute user commands unless settings are provided" args = ['noargs_command'] out, err = self.run_django_admin(args) self.assertNoOutput(out) self.assertOutput(err, "Unknown command: 'noargs_command'") def test_custom_command_with_settings(self): - "fulldefault: django-admin can't execute user commands, even if settings are provided as argument" + "fulldefault: django-admin can execute user commands if settings are provided as argument" args = ['noargs_command', '--settings=settings'] out, err = self.run_django_admin(args) - self.assertNoOutput(out) - self.assertOutput(err, "Unknown command: 'noargs_command'") + self.assertNoOutput(err) + self.assertOutput(out, "EXECUTE:NoArgsCommand") def test_custom_command_with_environment(self): - "fulldefault: django-admin can't execute user commands, even if settings are provided in environment" + "fulldefault: django-admin can execute user commands if settings are provided in environment" args = ['noargs_command'] out, err = self.run_django_admin(args,'settings') - self.assertNoOutput(out) - self.assertOutput(err, "Unknown command: 'noargs_command'") + self.assertNoOutput(err) + self.assertOutput(out, "EXECUTE:NoArgsCommand") class DjangoAdminMinimalSettings(AdminScriptTestCase): """A series of tests for django-admin.py when using a settings.py file that @@ -355,7 +355,7 @@ class DjangoAdminMinimalSettings(AdminScriptTestCase): self.assertOutput(err, "Could not import settings 'bad_settings'") def test_custom_command(self): - "minimal: django-admin can't execute user commands" + "minimal: django-admin can't execute user commands unless settings are provided" args = ['noargs_command'] out, err = self.run_django_admin(args) self.assertNoOutput(out) @@ -420,26 +420,26 @@ class DjangoAdminAlternateSettings(AdminScriptTestCase): self.assertNoOutput(out) self.assertOutput(err, "Could not import settings 'bad_settings'") - def test_custom_command(self): - "alternate: django-admin can't execute user commands" + def test_custom_command(self): + "alternate: django-admin can't execute user commands unless settings are provided" args = ['noargs_command'] out, err = self.run_django_admin(args) self.assertNoOutput(out) self.assertOutput(err, "Unknown command: 'noargs_command'") def test_custom_command_with_settings(self): - "alternate: django-admin can't execute user commands, even if settings are provided as argument" + "alternate: django-admin can execute user commands if settings are provided as argument" args = ['noargs_command', '--settings=alternate_settings'] out, err = self.run_django_admin(args) - self.assertNoOutput(out) - self.assertOutput(err, "Unknown command: 'noargs_command'") + self.assertNoOutput(err) + self.assertOutput(out, "EXECUTE:NoArgsCommand") def test_custom_command_with_environment(self): - "alternate: django-admin can't execute user commands, even if settings are provided in environment" + "alternate: django-admin can execute user commands if settings are provided in environment" args = ['noargs_command'] out, err = self.run_django_admin(args,'alternate_settings') - self.assertNoOutput(out) - self.assertOutput(err, "Unknown command: 'noargs_command'") + self.assertNoOutput(err) + self.assertOutput(out, "EXECUTE:NoArgsCommand") class DjangoAdminMultipleSettings(AdminScriptTestCase): @@ -490,8 +490,8 @@ class DjangoAdminMultipleSettings(AdminScriptTestCase): self.assertNoOutput(out) self.assertOutput(err, "Could not import settings 'bad_settings'") - def test_custom_command(self): - "alternate: django-admin can't execute user commands" + def test_custom_command(self): + "alternate: django-admin can't execute user commands unless settings are provided" args = ['noargs_command'] out, err = self.run_django_admin(args) self.assertNoOutput(out) @@ -501,15 +501,15 @@ class DjangoAdminMultipleSettings(AdminScriptTestCase): "alternate: django-admin can't execute user commands, even if settings are provided as argument" args = ['noargs_command', '--settings=alternate_settings'] out, err = self.run_django_admin(args) - self.assertNoOutput(out) - self.assertOutput(err, "Unknown command: 'noargs_command'") + self.assertNoOutput(err) + self.assertOutput(out, "EXECUTE:NoArgsCommand") def test_custom_command_with_environment(self): "alternate: django-admin can't execute user commands, even if settings are provided in environment" args = ['noargs_command'] out, err = self.run_django_admin(args,'alternate_settings') - self.assertNoOutput(out) - self.assertOutput(err, "Unknown command: 'noargs_command'") + self.assertNoOutput(err) + self.assertOutput(out, "EXECUTE:NoArgsCommand") ########################################################################## # MANAGE.PY TESTS