Index: django/core/management.py
===================================================================
--- django/core/management.py	(revision 4401)
+++ django/core/management.py	(working copy)
@@ -1222,9 +1222,9 @@
     from django.db.models import get_app, get_apps
 
     if len(app_labels) == 0:
-        app_list = get_apps()
+        app_list = get_apps(True)
     else:
-        app_list = [get_app(app_label) for app_label in app_labels]
+        app_list = [get_app(app_label,return_package=True) for app_label in app_labels]
 
     test_path = settings.TEST_RUNNER.split('.')
     # Allow for Python 2.5 relative paths
Index: django/db/models/loading.py
===================================================================
--- django/db/models/loading.py	(revision 4401)
+++ django/db/models/loading.py	(working copy)
@@ -7,20 +7,24 @@
 
 __all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models')
 
-_app_list = []   # Cache of installed apps.
-                 # Entry is not placed in app_list cache until entire app is loaded.
-_app_models = {} # Dictionary of models against app label
-                 # Each value is a dictionary of model name: model class
-                 # Applabel and Model entry exists in cache when individual model is loaded.
-_app_errors = {} # Dictionary of errors that were experienced when loading the INSTALLED_APPS
-                 # Key is the app_name of the model, value is the exception that was raised
-                 # during model loading.
-_loaded = False  # Has the contents of settings.INSTALLED_APPS been loaded?
-                 # i.e., has get_apps() been called?
+_app_list = []      # Cache of installed apps.
+                    # Entry is not placed in app_list cache until entire app is loaded.
+_app_pckg_list = [] # Similar to _app_list but will have the application package insted of
+                    # the models module. Unlike _app_list, list will also include applications
+                    # that do not define models.
+_app_models = {}    # Dictionary of models against app label
+                    # Each value is a dictionary of model name: model class
+                    # Applabel and Model entry exists in cache when individual model is loaded.
+_app_errors = {}    # Dictionary of errors that were experienced when loading the INSTALLED_APPS
+                    # Key is the app_name of the model, value is the exception that was raised
+                    # during model loading.
+_loaded = False     # Has the contents of settings.INSTALLED_APPS been loaded?
+                    # i.e., has get_apps() been called?
 
-def get_apps():
-    "Returns a list of all installed modules that contain models."
+def get_apps(return_package=False):
+    "Returns a list of all installed modules that contain models. If return_package is True it will return all application packages in INSTALLED_APPS."
     global _app_list
+    global _app_pckg_list
     global _loaded
     if not _loaded:
         _loaded = True
@@ -30,29 +34,42 @@
             except Exception, e:
                 # Problem importing the app
                 _app_errors[app_name] = e
+    if return_package:
+        return _app_pckg_list
     return _app_list
 
-def get_app(app_label, emptyOK=False):
-    "Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None."
+def get_app(app_label, emptyOK=False, return_package=False):
+    "Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None. Otherwise, if return_package is True, will return the package of the application."
     get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
     for app_name in settings.INSTALLED_APPS:
         if app_label == app_name.split('.')[-1]:
-            mod = load_app(app_name)
-            if mod is None:
-                if emptyOK:
-                    return None
+            if return_package:
+                pckg = load_app(app_name,True)
+                if pckg:
+                    return pckg
             else:
-                return mod
+                mod = load_app(app_name)
+                if mod is None:
+                    if emptyOK:
+                        return None
+                else:
+                    return mod
     raise ImproperlyConfigured, "App with label %s could not be found" % app_label
 
-def load_app(app_name):
-    "Loads the app with the provided fully qualified name, and returns the model module."
+def load_app(app_name, return_package=False):
+    "Loads the app with the provided fully qualified name, and returns the model module. If return_package is True, will return the application package instead."
     global _app_list
     mod = __import__(app_name, {}, {}, ['models'])
+    if mod not in _app_pckg_list:
+        _app_pckg_list.append(mod)
     if not hasattr(mod, 'models'):
+        if return_package:
+            return mod
         return None
     if mod.models not in _app_list:
         _app_list.append(mod.models)
+    if return_package:
+        return mod
     return mod.models
 
 def get_app_errors():
Index: django/test/simple.py
===================================================================
--- django/test/simple.py	(revision 4401)
+++ django/test/simple.py	(working copy)
@@ -7,32 +7,35 @@
 
 # The module name for tests outside models.py
 TEST_MODULE = 'tests'
-    
+
 doctestOutputChecker = OutputChecker()
 
-def build_suite(app_module):
+def build_suite(app_package):
     "Create a complete Django test suite for the provided application module"
     suite = unittest.TestSuite()
     
-    # Load unit and doctests in the models.py file
-    suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module))
-    try:
-        suite.addTest(doctest.DocTestSuite(app_module,
-                                           checker=doctestOutputChecker,
-                                           runner=DocTestRunner))
-    except ValueError:
-        # No doc tests in models.py
-        pass
-    
-    # Check to see if a separate 'tests' module exists parallel to the 
+    if hasattr(app_package,'models'):
+        app_module = app_package.models
+
+        # Load unit and doctests in the models.py file
+        suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module))
+        try:
+            suite.addTest(doctest.DocTestSuite(app_module,
+                                               checker=doctestOutputChecker,
+                                               runner=DocTestRunner))
+        except ValueError:
+            # No doc tests in models.py
+            pass
+
+    # Check to see if a separate 'tests' module exists parallel to the
     # models module
     try:
-        app_path = app_module.__name__.split('.')[:-1]
+        app_path = app_package.__name__.split('.')[:-1]
         test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE)
-        
+
         suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module))
-        try:            
-            suite.addTest(doctest.DocTestSuite(test_module, 
+        try:
+            suite.addTest(doctest.DocTestSuite(test_module,
                                                checker=doctestOutputChecker,
                                                runner=DocTestRunner))
         except ValueError:
@@ -44,20 +47,20 @@
         import os.path
         from imp import find_module
         try:
-            mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)])
+            mod = find_module(TEST_MODULE, [os.path.dirname(app_package.__file__)])
         except ImportError:
             # 'tests' module doesn't exist. Move on.
             pass
         else:
-            # The module exists, so there must be an import error in the 
+            # The module exists, so there must be an import error in the
             # test module itself. We don't need the module; close the file
             # handle returned by find_module.
             mod[0].close()
             raise
-            
+
     return suite
 
-def run_tests(module_list, verbosity=1, extra_tests=[]):
+def run_tests(package_list, verbosity=1, extra_tests=[]):
     """
     Run the unit tests for all the modules in the provided list.
     This testrunner will search each of the modules in the provided list,
@@ -66,13 +69,13 @@
     will be added to the test suite.
     """
     setup_test_environment()
-    
-    settings.DEBUG = False    
+
+    settings.DEBUG = False
     suite = unittest.TestSuite()
-     
-    for module in module_list:
-        suite.addTest(build_suite(module))
-    
+
+    for package in package_list:
+        suite.addTest(build_suite(package))
+
     for test in extra_tests:
         suite.addTest(test)
 
@@ -81,5 +84,5 @@
     management.syncdb(verbosity, interactive=False)
     unittest.TextTestRunner(verbosity=verbosity).run(suite)
     destroy_test_db(old_name, verbosity)
-    
+
     teardown_test_environment()
