diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index 8e83304..74bb558 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -3,11 +3,12 @@ import os
 import sys
 from optparse import OptionParser, NO_DEFAULT
 import imp
+import pkgutil
 import warnings
 
 from django.core.management.base import BaseCommand, CommandError, handle_default_options
 from django.core.management.color import color_style
-from django.utils.importlib import import_module
+from django.utils.importlib import import_module, find_package_path
 
 # For backwards compatibility: get_version() used to be in this module.
 from django import get_version
@@ -23,11 +24,11 @@ def find_commands(management_dir):
 
     Returns an empty list if no commands are defined.
     """
-    command_dir = os.path.join(management_dir, 'commands')
     try:
-        return [f[:-3] for f in os.listdir(command_dir)
-                if not f.startswith('_') and f.endswith('.py')]
-    except OSError:
+        commands_dir = find_package_path('commands', [management_dir])[0]
+        return [name for loader,name,ispkg in pkgutil.iter_modules([commands_dir])
+                if not name.startswith('_') ]
+    except ImportError:
         return []
 
 def find_management_module(app_name):
@@ -39,26 +40,39 @@ def find_management_module(app_name):
     """
     parts = app_name.split('.')
     parts.append('management')
-    parts.reverse()
-    part = parts.pop()
-    path = None
-
-    # When using manage.py, the project module is added to the path,
-    # loaded, then removed from the path. This means that
-    # testproject.testapp.models can be loaded in future, even if
-    # testproject isn't in the path. When looking for the management
-    # module, we need look for the case where the project name is part
-    # of the app_name but the project directory itself isn't on the path.
-    try:
-        f, path, descr = imp.find_module(part,path)
-    except ImportError,e:
-        if os.path.basename(os.getcwd()) != part:
-            raise e
+
+    for i in range(len(parts), 0, -1):
+        try:
+            path = sys.modules['.'.join(parts[:i])].__path__
+        except AttributeError:
+            raise ImportError("No package named %s" % parts[i-1])
+        except KeyError:
+            continue
+
+        parts = parts[i:]
+        parts.reverse()
+        break
+    else:
+        parts.reverse()
+        part = parts.pop()
+        path = None
+
+        # When using manage.py, the project module is added to the path,
+        # loaded, then removed from the path. This means that
+        # testproject.testapp.models can be loaded in future, even if
+        # testproject isn't in the path. When looking for the management
+        # module, we need look for the case where the project name is part
+        # of the app_name but the project directory itself isn't on the path.
+        try:
+            path = find_package_path(part, path)
+        except ImportError,e:
+            if os.path.basename(os.getcwd()) != part:
+                raise e
 
     while parts:
         part = parts.pop()
-        f, path, descr = imp.find_module(part, path and [path] or None)
-    return path
+        path = find_package_path(part, path)
+    return path[0]
 
 def load_command_class(app_name, name):
     """
diff --git a/django/db/utils.py b/django/db/utils.py
index 3f5b86e..5c4740f 100644
--- a/django/db/utils.py
+++ b/django/db/utils.py
@@ -1,5 +1,6 @@
 import os
 from threading import local
+import pkgutil
 
 from django.conf import settings
 from django.core.exceptions import ImproperlyConfigured
@@ -25,13 +26,10 @@ def load_backend(backend_name):
     except ImportError, e_user:
         # The database backend wasn't found. Display a helpful error message
         # listing all possible (built-in) database backends.
-        backend_dir = os.path.join(os.path.dirname(__file__), 'backends')
-        try:
-            available_backends = [f for f in os.listdir(backend_dir)
-                    if os.path.isdir(os.path.join(backend_dir, f))
-                    and not f.startswith('.')]
-        except EnvironmentError:
-            available_backends = []
+        backend_path = import_module('django.db.backends').__path__
+        available_backends = [ name for loader, name, ispkg
+                in pkgutil.iter_modules(backend_path)
+                if ispkg ]
         full_notation = backend_name.startswith('django.db.backends.')
         if full_notation:
             backend_name = backend_name[19:] # See #15621.
diff --git a/django/template/loader.py b/django/template/loader.py
index 4185017..98ea96c 100644
--- a/django/template/loader.py
+++ b/django/template/loader.py
@@ -3,10 +3,9 @@
 # This uses the TEMPLATE_LOADERS setting, which is a list of loaders to use.
 # Each loader is expected to have this interface:
 #
-#    callable(name, dirs=[])
+#    callable(name)
 #
 # name is the template name.
-# dirs is an optional list of directories to search instead of TEMPLATE_DIRS.
 #
 # The loader should return a tuple of (template_source, path). The path returned
 # might be shown to the user for debugging purposes, so it should identify where
@@ -38,12 +37,12 @@ class BaseLoader(object):
     def __init__(self, *args, **kwargs):
         pass
 
-    def __call__(self, template_name, template_dirs=None):
-        return self.load_template(template_name, template_dirs)
+    def __call__(self, template_name):
+        return self.load_template(template_name)
 
-    def load_template(self, template_name, template_dirs=None):
-        source, display_name = self.load_template_source(template_name, template_dirs)
-        origin = make_origin(display_name, self.load_template_source, template_name, template_dirs)
+    def load_template(self, template_name):
+        source, display_name = self.load_template_source(template_name)
+        origin = make_origin(display_name, self.load_template_source, template_name)
         try:
             template = get_template_from_string(source, origin, template_name)
             return template, None
@@ -54,7 +53,7 @@ class BaseLoader(object):
             # not exist.
             return source, display_name
 
-    def load_template_source(self, template_name, template_dirs=None):
+    def load_template_source(self, template_name):
         """
         Returns a tuple containing the source and origin for the given template
         name.
@@ -71,16 +70,16 @@ class BaseLoader(object):
         pass
 
 class LoaderOrigin(Origin):
-    def __init__(self, display_name, loader, name, dirs):
+    def __init__(self, display_name, loader, name):
         super(LoaderOrigin, self).__init__(display_name)
-        self.loader, self.loadname, self.dirs = loader, name, dirs
+        self.loader, self.loadname = loader, name
 
     def reload(self):
-        return self.loader(self.loadname, self.dirs)[0]
+        return self.loader(self.loadname)[0]
 
-def make_origin(display_name, loader, name, dirs):
+def make_origin(display_name, loader, name):
     if settings.TEMPLATE_DEBUG and display_name:
-        return LoaderOrigin(display_name, loader, name, dirs)
+        return LoaderOrigin(display_name, loader, name)
     else:
         return None
 
@@ -117,7 +116,7 @@ def find_template_loader(loader):
     else:
         raise ImproperlyConfigured('Loader does not define a "load_template" callable template source loader')
 
-def find_template(name, dirs=None):
+def find_template(name):
     # Calculate template_source_loaders the first time the function is executed
     # because putting this logic in the module-level namespace may cause
     # circular import errors. See Django ticket #1292.
@@ -131,8 +130,8 @@ def find_template(name, dirs=None):
         template_source_loaders = tuple(loaders)
     for loader in template_source_loaders:
         try:
-            source, display_name = loader(name, dirs)
-            return (source, make_origin(display_name, loader, name, dirs))
+            source, display_name = loader(name)
+            return (source, make_origin(display_name, loader, name))
         except TemplateDoesNotExist:
             pass
     raise TemplateDoesNotExist(name)
diff --git a/django/template/loaders/app_directories.py b/django/template/loaders/app_directories.py
index b0560b4..2db1a47 100644
--- a/django/template/loaders/app_directories.py
+++ b/django/template/loaders/app_directories.py
@@ -3,62 +3,27 @@ Wrapper for loading templates from "templates" directories in INSTALLED_APPS
 packages.
 """
 
-import os
-import sys
+import pkgutil
 
 from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured
 from django.template.base import TemplateDoesNotExist
 from django.template.loader import BaseLoader
 from django.utils._os import safe_join
-from django.utils.importlib import import_module
 
-# At compile time, cache the directories to search.
-fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
-app_template_dirs = []
-for app in settings.INSTALLED_APPS:
-    try:
-        mod = import_module(app)
-    except ImportError, e:
-        raise ImproperlyConfigured('ImportError %s: %s' % (app, e.args[0]))
-    template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates')
-    if os.path.isdir(template_dir):
-        app_template_dirs.append(template_dir.decode(fs_encoding))
-
-# It won't change, so convert it to a tuple to save memory.
-app_template_dirs = tuple(app_template_dirs)
 
 class Loader(BaseLoader):
     is_usable = True
 
-    def get_template_sources(self, template_name, template_dirs=None):
-        """
-        Returns the absolute paths to "template_name", when appended to each
-        directory in "template_dirs". Any paths that don't lie inside one of the
-        template dirs are excluded from the result set, for security reasons.
-        """
-        if not template_dirs:
-            template_dirs = app_template_dirs
-        for template_dir in template_dirs:
+    def load_template_source(self, template_name):
+        for app in settings.INSTALLED_APPS:
+            resource = safe_join('/templates', template_name)[1:]
             try:
-                yield safe_join(template_dir, template_name)
-            except UnicodeDecodeError:
-                # The template dir name was a bytestring that wasn't valid UTF-8.
-                raise
-            except ValueError:
-                # The joined path was located outside of template_dir.
+                data = pkgutil.get_data(app, resource)
+                if data is not None:
+                    return data, 'app:' + app + ':'+resource
+            except Exception:
                 pass
 
-    def load_template_source(self, template_name, template_dirs=None):
-        for filepath in self.get_template_sources(template_name, template_dirs):
-            try:
-                file = open(filepath)
-                try:
-                    return (file.read().decode(settings.FILE_CHARSET), filepath)
-                finally:
-                    file.close()
-            except IOError:
-                pass
         raise TemplateDoesNotExist(template_name)
 
 _loader = Loader()
diff --git a/django/template/loaders/cached.py b/django/template/loaders/cached.py
index 4c25acd..eeb1e6e 100644
--- a/django/template/loaders/cached.py
+++ b/django/template/loaders/cached.py
@@ -27,23 +27,18 @@ class Loader(BaseLoader):
             self._cached_loaders = cached_loaders
         return self._cached_loaders
 
-    def find_template(self, name, dirs=None):
+    def find_template(self, name):
         for loader in self.loaders:
             try:
-                template, display_name = loader(name, dirs)
-                return (template, make_origin(display_name, loader, name, dirs))
+                template, display_name = loader(name)
+                return (template, make_origin(display_name, loader, name))
             except TemplateDoesNotExist:
                 pass
         raise TemplateDoesNotExist(name)
 
-    def load_template(self, template_name, template_dirs=None):
-        key = template_name
-        if template_dirs:
-            # If template directories were specified, use a hash to differentiate
-            key = '-'.join([template_name, hashlib.sha1('|'.join(template_dirs)).hexdigest()])
-
-        if key not in self.template_cache:
-            template, origin = self.find_template(template_name, template_dirs)
+    def load_template(self, template_name):
+        if template_name not in self.template_cache:
+            template, origin = self.find_template(template_name)
             if not hasattr(template, 'render'):
                 try:
                     template = get_template_from_string(template, origin, template_name)
@@ -53,8 +48,8 @@ class Loader(BaseLoader):
                     # we were asked to load. This allows for correct identification (later)
                     # of the actual template that does not exist.
                     return template, origin
-            self.template_cache[key] = template
-        return self.template_cache[key], None
+            self.template_cache[template_name] = template
+        return self.template_cache[template_name], None
 
     def reset(self):
         "Empty the template cache."
diff --git a/django/template/loaders/eggs.py b/django/template/loaders/eggs.py
deleted file mode 100644
index 42f87a4..0000000
--- a/django/template/loaders/eggs.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Wrapper for loading templates from eggs via pkg_resources.resource_string.
-
-try:
-    from pkg_resources import resource_string
-except ImportError:
-    resource_string = None
-
-from django.template.base import TemplateDoesNotExist
-from django.template.loader import BaseLoader
-from django.conf import settings
-
-class Loader(BaseLoader):
-    is_usable = resource_string is not None
-
-    def load_template_source(self, template_name, template_dirs=None):
-        """
-        Loads templates from Python eggs via pkg_resource.resource_string.
-
-        For every installed app, it tries to get the resource (app, template_name).
-        """
-        if resource_string is not None:
-            pkg_name = 'templates/' + template_name
-            for app in settings.INSTALLED_APPS:
-                try:
-                    return (resource_string(app, pkg_name).decode(settings.FILE_CHARSET), 'egg:%s:%s' % (app, pkg_name))
-                except:
-                    pass
-        raise TemplateDoesNotExist(template_name)
-
-_loader = Loader()
diff --git a/django/template/loaders/filesystem.py b/django/template/loaders/filesystem.py
index 51025ac..b926c6b 100644
--- a/django/template/loaders/filesystem.py
+++ b/django/template/loaders/filesystem.py
@@ -10,15 +10,16 @@ from django.utils._os import safe_join
 class Loader(BaseLoader):
     is_usable = True
 
-    def get_template_sources(self, template_name, template_dirs=None):
+    def __init__(self, template_dirs=None):
+        self.template_dirs = template_dirs or settings.TEMPLATE_DIRS
+
+    def get_template_sources(self, template_name):
         """
         Returns the absolute paths to "template_name", when appended to each
         directory in "template_dirs". Any paths that don't lie inside one of the
         template dirs are excluded from the result set, for security reasons.
         """
-        if not template_dirs:
-            template_dirs = settings.TEMPLATE_DIRS
-        for template_dir in template_dirs:
+        for template_dir in self.template_dirs:
             try:
                 yield safe_join(template_dir, template_name)
             except UnicodeDecodeError:
@@ -30,9 +31,9 @@ class Loader(BaseLoader):
                 # fatal).
                 pass
 
-    def load_template_source(self, template_name, template_dirs=None):
+    def load_template_source(self, template_name):
         tried = []
-        for filepath in self.get_template_sources(template_name, template_dirs):
+        for filepath in self.get_template_sources(template_name):
             try:
                 file = open(filepath)
                 try:
diff --git a/django/utils/importlib.py b/django/utils/importlib.py
index ef4d0e4..f53abd9 100644
--- a/django/utils/importlib.py
+++ b/django/utils/importlib.py
@@ -1,5 +1,9 @@
 # Taken from Python 2.7 with permission from/by the original author.
+import os
 import sys
+import imp
+import pkgutil
+import warnings
 
 def _resolve_name(name, package, level):
     """Return the absolute name of the module to be imported."""
@@ -34,3 +38,86 @@ def import_module(name, package=None):
         name = _resolve_name(name[level:], package, level)
     __import__(name)
     return sys.modules[name]
+
+
+def find_package_path(name, path=None):
+    """Finds search path for package with given name.
+
+    The 'path' argument defaults to ``sys.path``.
+
+    Raises ImportError if no search path could be found.
+    """
+    if path is None:
+        path = sys.path
+
+    results = []
+
+    for path_item in path:
+        importer = get_importer(path_item)
+
+        if importer is None:
+            continue
+
+        try:
+            loader = importer.find_module(name)
+
+            if loader is not None:
+
+                if not hasattr(loader, 'is_package'):
+                    warnings.warn(
+                        "Django cannot find search path for package '%s' ",
+                        "under '%s', because the loader returned by '%s' does ",
+                        "not implement 'is_package' method."%(
+                            name,
+                            path_item,
+                            importer.__class__.__name__))
+                    continue
+
+                if not hasattr(loader, 'get_filename'):
+                    warnings.warn(
+                        "Django cannot find search path for package '%s' ",
+                        "under '%s', because the loader returned by '%s' does ",
+                        "not implement 'get_filename' method."%(
+                            name,
+                            path_item,
+                            importer.__class__.__name__))
+                    continue
+
+                if loader.is_package(name):
+                    results.append(os.path.dirname(loader.get_filename(name)))
+        except ImportError:
+            pass
+
+    if not results:
+        raise ImportError("No package named %s" % name)
+
+    return results
+
+
+get_importer = pkgutil.get_importer
+
+try:
+    import zipimport
+
+    if hasattr(zipimport.zipimporter, 'get_filename'):
+        class ZipImporter(zipimport.zipimporter):
+            def get_filename(self, fullname):
+                archivepath = os.path.join(self.archive, self.prefix)
+                if self.is_package(fullname):
+                    return os.path.join(archivepath, fullname, '__init__.py')
+
+                return os.path.join(archivepath, fullname + '.py')
+
+        def get_importer(path_item):
+            importer = pkgutil.get_importer(path_item)
+
+            if isinstance(importer, zipimport.zipimporter):
+                archivepath = os.path.join(importer.archive, importer.prefix)
+                importer = ZipImporter(os.path.dirname(archivepath))
+
+            return importer
+
+except ImportError:
+    pass
+
+
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index 82072b1..115f964 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -6,6 +6,8 @@ import re
 import sys
 import gettext as gettext_module
 from threading import local
+import pkgutil
+import copy
 
 try:
     from cStringIO import StringIO
@@ -111,13 +113,6 @@ def translation(language):
 
     globalpath = os.path.join(os.path.dirname(sys.modules[settings.__module__].__file__), 'locale')
 
-    if settings.SETTINGS_MODULE is not None:
-        parts = settings.SETTINGS_MODULE.split('.')
-        project = import_module(parts[0])
-        projectpath = os.path.join(os.path.dirname(project.__file__), 'locale')
-    else:
-        projectpath = None
-
     def _fetch(lang, fallback=None):
 
         global _translations
@@ -128,13 +123,30 @@ def translation(language):
 
         loc = to_locale(lang)
 
-        def _translation(path):
-            try:
-                t = gettext_module.translation('django', path, [loc], DjangoTranslation)
-                t.set_language(lang)
-                return t
-            except IOError:
-                return None
+        def _translation(path_or_appname, is_appname=False):
+            if is_appname:
+                nelangs = gettext_module._expand_lang(loc)
+                for nelang in nelangs:
+                    locpath = os.path.join('locale', nelang, 'LC_MESSAGES', 'django.mo')
+                    try:
+                        data = pkgutil.get_data(path_or_appname, locpath)
+                    except:
+                        continue
+
+                    if data is not None:
+                        t = DjangoTranslation(StringIO(data))
+                        t = copy.copy(t)
+                        break
+                else:
+                    return None
+            else:
+                try:
+                    t = gettext_module.translation('django', path_or_appname, [loc], DjangoTranslation)
+                except IOError:
+                    return None
+
+            t.set_language(lang)
+            return t
 
         res = _translation(globalpath)
 
@@ -147,8 +159,8 @@ def translation(language):
             res._info = res._info.copy()
             res._catalog = res._catalog.copy()
 
-        def _merge(path):
-            t = _translation(path)
+        def _merge(path_or_appname, is_appname=False):
+            t = _translation(path_or_appname, is_appname)
             if t is not None:
                 if res is None:
                     return t
@@ -157,16 +169,9 @@ def translation(language):
             return res
 
         for appname in reversed(settings.INSTALLED_APPS):
-            app = import_module(appname)
-            apppath = os.path.join(os.path.dirname(app.__file__), 'locale')
-
-            if os.path.isdir(apppath):
-                res = _merge(apppath)
+            res = _merge(appname, is_appname=True)
 
-        localepaths = [os.path.normpath(path) for path in settings.LOCALE_PATHS]
-        if (projectpath and os.path.isdir(projectpath) and
-                os.path.normpath(projectpath) not in localepaths):
-            res = _merge(projectpath)
+        res = _merge(settings.SETTINGS_MODULE, is_appname=True)
 
         for localepath in reversed(settings.LOCALE_PATHS):
             if os.path.isdir(localepath):
diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
index 03fef1d..8154d2c 100644
--- a/docs/ref/templates/api.txt
+++ b/docs/ref/templates/api.txt
@@ -655,9 +655,9 @@ class. Here are the template loaders that come with Django:
     This loader is enabled by default.
 
 ``django.template.loaders.app_directories.Loader``
-    Loads templates from Django apps on the filesystem. For each app in
-    :setting:`INSTALLED_APPS`, the loader looks for a ``templates``
-    subdirectory. If the directory exists, Django looks for templates in there.
+    Loads templates from Django apps. For each app in :setting:`INSTALLED_APPS`,
+    the loader looks for a ``templates`` subdirectory. If the directory exists, 
+    Django looks for templates in there.
 
     This means you can store templates with your individual apps. This also
     makes it easy to distribute Django apps with default templates.
@@ -672,18 +672,8 @@ class. Here are the template loaders that come with Django:
     * ``/path/to/myproject/polls/templates/foo.html``
     * ``/path/to/myproject/music/templates/foo.html``
 
-    Note that the loader performs an optimization when it is first imported: It
-    caches a list of which :setting:`INSTALLED_APPS` packages have a
-    ``templates`` subdirectory.
-
     This loader is enabled by default.
 
-``django.template.loaders.eggs.Loader``
-    Just like ``app_directories`` above, but it loads templates from Python
-    eggs rather than from the filesystem.
-
-    This loader is disabled by default.
-
 ``django.template.loaders.cached.Loader``
     By default, the templating system will read and compile your templates every
     time they need to be rendered. While the Django templating system is quite
@@ -838,8 +828,8 @@ of the ``load_template_source()`` method implemented there::
     class Loader(app_directories.Loader):
         is_usable = True
 
-        def load_template(self, template_name, template_dirs=None):
-            source, origin = self.load_template_source(template_name, template_dirs)
+        def load_template(self, template_name):
+            source, origin = self.load_template_source(template_name)
             template = Template(source)
             return template, origin
 
diff --git a/tests/regressiontests/admin_scripts/lib1/nons_app/__init__.py b/tests/regressiontests/admin_scripts/lib1/nons_app/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/nons_app/management/__init__.py b/tests/regressiontests/admin_scripts/lib1/nons_app/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/nons_app/management/commands/__init__.py b/tests/regressiontests/admin_scripts/lib1/nons_app/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/nons_app/management/commands/nons_app_command1.py b/tests/regressiontests/admin_scripts/lib1/nons_app/management/commands/nons_app_command1.py
new file mode 100644
index 0000000..a393663
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib1/nons_app/management/commands/nons_app_command1.py
@@ -0,0 +1,9 @@
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+    help = 'Test managment commands in non-namespaced app'
+    requires_model_validation = False
+    args = ''
+
+    def handle(self, *labels, **options):
+        print 'EXECUTE:nons_app_command1'
diff --git a/tests/regressiontests/admin_scripts/lib1/nons_app/models.py b/tests/regressiontests/admin_scripts/lib1/nons_app/models.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/npapp/__init__.py b/tests/regressiontests/admin_scripts/lib1/npapp/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/npapp/management.py b/tests/regressiontests/admin_scripts/lib1/npapp/management.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/npapp/models.py b/tests/regressiontests/admin_scripts/lib1/npapp/models.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/__init__.py b/tests/regressiontests/admin_scripts/lib1/nsapps/__init__.py
new file mode 100644
index 0000000..32f26d8
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib1/nsapps/__init__.py
@@ -0,0 +1,6 @@
+# http://packages.python.org/distribute/setuptools.html#namespace-packages
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/__init__.py b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/__init__.py
new file mode 100644
index 0000000..32f26d8
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/__init__.py
@@ -0,0 +1,6 @@
+# http://packages.python.org/distribute/setuptools.html#namespace-packages
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/__init__.py b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/management/__init__.py b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/management/commands/__init__.py b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/management/commands/app1_command1.py b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/management/commands/app1_command1.py
new file mode 100644
index 0000000..2f479bb
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/management/commands/app1_command1.py
@@ -0,0 +1,9 @@
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+    help = 'Test managment commands in namespaced apps'
+    requires_model_validation = False
+    args = ''
+
+    def handle(self, *labels, **options):
+        print 'EXECUTE:app1_command1'
diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/models.py b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/models.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/__init__.py b/tests/regressiontests/admin_scripts/lib2/nsapps/__init__.py
new file mode 100644
index 0000000..32f26d8
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib2/nsapps/__init__.py
@@ -0,0 +1,6 @@
+# http://packages.python.org/distribute/setuptools.html#namespace-packages
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/__init__.py b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/__init__.py
new file mode 100644
index 0000000..32f26d8
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/__init__.py
@@ -0,0 +1,6 @@
+# http://packages.python.org/distribute/setuptools.html#namespace-packages
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/__init__.py b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/management/__init__.py b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/management/commands/__init__.py b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/management/commands/app2_command1.py b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/management/commands/app2_command1.py
new file mode 100644
index 0000000..b9e20a7
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/management/commands/app2_command1.py
@@ -0,0 +1,9 @@
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+    help = 'Test managment commands in namespaced apps'
+    requires_model_validation = False
+    args = ''
+
+    def handle(self, *labels, **options):
+        print 'EXECUTE:app2_command1'
diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/models.py b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/models.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib3/_addsitedir.py b/tests/regressiontests/admin_scripts/lib3/_addsitedir.py
new file mode 100644
index 0000000..9e264d2
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib3/_addsitedir.py
@@ -0,0 +1 @@
+import os.path, site; site.addsitedir(os.path.dirname(__file__))
diff --git a/tests/regressiontests/admin_scripts/lib3/egg_module.pth b/tests/regressiontests/admin_scripts/lib3/egg_module.pth
new file mode 100644
index 0000000..9367ab5
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib3/egg_module.pth
@@ -0,0 +1 @@
+test_egg.egg
diff --git a/tests/regressiontests/admin_scripts/lib3/exapps-nspkg.pth b/tests/regressiontests/admin_scripts/lib3/exapps-nspkg.pth
new file mode 100644
index 0000000..1f31155
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib3/exapps-nspkg.pth
@@ -0,0 +1 @@
+import sys,new,os; p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('exapps',)); ie = os.path.exists(os.path.join(p,'__init__.py')); m = not ie and sys.modules.setdefault('exapps',new.module('exapps')); mp = (m or []) and m.__dict__.setdefault('__path__',[]); (p not in mp) and mp.append(p)
diff --git a/tests/regressiontests/admin_scripts/lib3/exapps/app3/__init__.py b/tests/regressiontests/admin_scripts/lib3/exapps/app3/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/__init__.py b/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/commands/__init__.py b/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/commands/app3_command1.py b/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/commands/app3_command1.py
new file mode 100644
index 0000000..97f5d33
--- /dev/null
+++ b/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/commands/app3_command1.py
@@ -0,0 +1,9 @@
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+    help = 'Test managment commands in namespaced apps'
+    requires_model_validation = False
+    args = ''
+
+    def handle(self, *labels, **options):
+        print 'EXECUTE:app3_command1'
diff --git a/tests/regressiontests/admin_scripts/lib3/exapps/app3/models.py b/tests/regressiontests/admin_scripts/lib3/exapps/app3/models.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/admin_scripts/lib3/test_egg.egg b/tests/regressiontests/admin_scripts/lib3/test_egg.egg
new file mode 100644
index 0000000000000000000000000000000000000000..d9e57de006a3d602515293f8e980bf3a16fb42c0
GIT binary patch
diff --git a/tests/regressiontests/admin_scripts/tests.py b/tests/regressiontests/admin_scripts/tests.py
index 669c6e8..6408b97 100644
--- a/tests/regressiontests/admin_scripts/tests.py
+++ b/tests/regressiontests/admin_scripts/tests.py
@@ -91,6 +91,10 @@ class AdminScriptTestCase(unittest.TestCase):
     def run_test(self, script, args, settings_file=None, apps=None):
         project_dir = os.path.dirname(test_dir)
         base_dir = os.path.dirname(project_dir)
+        lib1_dir = os.path.join(os.path.dirname(__file__), 'lib1')
+        lib2_dir = os.path.join(os.path.dirname(__file__), 'lib2')
+        lib3_dir = os.path.join(os.path.dirname(__file__), 'lib3')
+        eggs_dir = os.path.join(os.path.dirname(__file__), 'eggs')
         ext_backend_base_dirs = self._ext_backend_paths()
 
         # Remember the old environment
@@ -108,7 +112,7 @@ class AdminScriptTestCase(unittest.TestCase):
             os.environ['DJANGO_SETTINGS_MODULE'] = settings_file
         elif 'DJANGO_SETTINGS_MODULE' in os.environ:
             del os.environ['DJANGO_SETTINGS_MODULE']
-        python_path = [project_dir, base_dir]
+        python_path = [project_dir, base_dir, lib1_dir, lib2_dir, lib3_dir]
         python_path.extend(ext_backend_base_dirs)
         os.environ[python_path_var_name] = os.pathsep.join(python_path)
 
@@ -1563,3 +1567,95 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
         self.assertOutput(err, "Destination directory '%s' does not exist, please create it first." % testproject_dir)
         self.assertFalse(os.path.exists(testproject_dir))
 
+
+class NamespacePackagedApps(AdminScriptTestCase):
+    def setUp(self):
+        self.write_settings('settings.py', apps=['nons_app', 'nsapps.contrib.app1','nsapps.contrib.app2','exapps.app3', 'egg_module'])
+        settings_file = open(os.path.join(test_dir, 'settings.py'), 'a')
+        settings_file.write('import _addsitedir')
+        settings_file.close()
+        
+    def tearDown(self):
+        self.remove_settings('settings.py')
+
+    def test_help(self):
+        out, err = self.run_manage(['help'])
+        self.assertNoOutput(err)
+        self.assertOutput(out, "nons_app_command1")
+        self.assertOutput(out, "app1_command1")
+        self.assertOutput(out, "app2_command1")
+        self.assertOutput(out, "app3_command1")
+        self.assertOutput(out, "egg_command")
+
+    def test_nons_app(self):
+        args = ['nons_app_command1']
+        out, err = self.run_manage(args)
+        self.assertNoOutput(err)
+        self.assertOutput(out, "EXECUTE:nons_app_command1")
+
+    def test_nsapps(self):
+        args = ['app1_command1']
+        out, err = self.run_manage(args)
+        self.assertNoOutput(err)
+        self.assertOutput(out, "EXECUTE:app1_command1")
+
+        args = ['app2_command1']
+        out, err = self.run_manage(args)
+        self.assertNoOutput(err)
+        self.assertOutput(out, "EXECUTE:app2_command1")
+
+    def test_exapps(self):
+        args = ['app3_command1']
+        out, err = self.run_manage(args)
+        self.assertNoOutput(err)
+        self.assertOutput(out, "EXECUTE:app3_command1")
+
+    def test_exapps(self):
+        args = ['egg_command']
+        out, err = self.run_manage(args)
+        self.assertNoOutput(err)
+        self.assertOutput(out, "EXECUTE:egg_command")
+
+
+class PreloadedNamespacePackagedApps(AdminScriptTestCase):
+    def setUp(self):
+        self.write_settings('settings.py', apps=['nsapps.contrib.app1','nsapps.contrib.app2'])
+        settings_file = open(os.path.join(test_dir, 'settings.py'), 'a')
+        settings_file.write('import nsapps')
+        settings_file.close()
+        
+    def tearDown(self):
+        self.remove_settings('settings.py')
+
+    def test_help(self):
+        out, err = self.run_manage(['help'])
+        self.assertNoOutput(err)
+        self.assertOutput(out, "app1_command1")
+        self.assertOutput(out, "app2_command1")
+
+    def test_nsapps(self):
+        args = ['app1_command1']
+        out, err = self.run_manage(args)
+        self.assertNoOutput(err)
+        self.assertOutput(out, "EXECUTE:app1_command1")
+
+        args = ['app2_command1']
+        out, err = self.run_manage(args)
+        self.assertNoOutput(err)
+        self.assertOutput(out, "EXECUTE:app2_command1")
+
+
+class NonPackageManagementApps(AdminScriptTestCase):
+    def setUp(self):
+        self.write_settings('settings.py', apps=['npapp'])
+        settings_file = open(os.path.join(test_dir, 'settings.py'), 'a')
+        settings_file.write('import npapp.management')
+        settings_file.close()
+
+    def tearDown(self):
+        self.remove_settings('settings.py')
+
+    def test_help(self):
+        out, err = self.run_manage(['help'])
+        self.assertNoOutput(err)
+
diff --git a/tests/regressiontests/i18n/eggs/localeegg.egg b/tests/regressiontests/i18n/eggs/localeegg.egg
new file mode 100644
index 0000000000000000000000000000000000000000..c3b13d05d974f9bea7fddd20c88f8979f56026a5
GIT binary patch
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
index 99a55bd..5fbccaf 100644
--- a/tests/regressiontests/i18n/tests.py
+++ b/tests/regressiontests/i18n/tests.py
@@ -4,6 +4,7 @@ from __future__ import with_statement, absolute_import
 import datetime
 import decimal
 import os
+import sys
 import pickle
 from threading import local
 
@@ -892,6 +893,52 @@ class ProjectResolutionOrderI18NTests(ResolutionOrderI18NTests):
         with self.settings(INSTALLED_APPS=extended_apps):
             self.assertUgettext('Date/time', 'PROJECT')
 
+class EggResolutionOrderI18NTests(ResolutionOrderI18NTests):
+
+    def setUp(self):
+        self.old_path = sys.path[:]
+        self.egg_dir = '%s/eggs' % os.path.dirname(__file__)
+        egg_name = '%s/localeegg.egg' % self.egg_dir
+        sys.path.insert(0, egg_name)
+        super(EggResolutionOrderI18NTests, self).setUp()
+
+    def tearDown(self):
+        super(EggResolutionOrderI18NTests, self).tearDown()
+        sys.path = self.old_path
+
+class EggAppResolutionOrderI18NTests(EggResolutionOrderI18NTests):
+
+    def setUp(self):
+        self.old_installed_apps = settings.INSTALLED_APPS
+        settings.INSTALLED_APPS = ['resolution'] + list(settings.INSTALLED_APPS)
+        super(EggAppResolutionOrderI18NTests, self).setUp()
+
+    def tearDown(self):
+        settings.INSTALLED_APPS = self.old_installed_apps
+        super(EggAppResolutionOrderI18NTests, self).tearDown()
+
+    def test_app_translation(self):
+        self.assertUgettext('Date/time', 'APP')
+
+class EggProjectResolutionOrderI18NTests(EggResolutionOrderI18NTests):
+
+    def setUp(self):
+        self.old_settings_module = settings.SETTINGS_MODULE
+        settings.SETTINGS_MODULE = 'eggtests'
+        super(EggProjectResolutionOrderI18NTests, self).setUp()
+
+    def tearDown(self):
+        super(EggProjectResolutionOrderI18NTests, self).tearDown()
+        settings.SETTINGS_MODULE = self.old_settings_module
+
+    def test_project_translation(self):
+        self.assertUgettext('Date/time', 'PROJECT')
+
+    def test_project_override_app_translation(self):
+        extended_apps = list(settings.INSTALLED_APPS) + ['resolution']
+        with self.settings(INSTALLED_APPS=extended_apps):
+            self.assertUgettext('Date/time', 'PROJECT')
+
 class DjangoFallbackResolutionOrderI18NTests(ResolutionOrderI18NTests):
 
     def test_django_fallback(self):
diff --git a/tests/regressiontests/templates/eggs/templatesegg.egg b/tests/regressiontests/templates/eggs/templatesegg.egg
new file mode 100644
index 0000000000000000000000000000000000000000..9a8f315f883b1d895f1d5926ca7ad3134c23287f
GIT binary patch
diff --git a/tests/regressiontests/templates/loaders.py b/tests/regressiontests/templates/loaders.py
index 5c11916..287bfdd 100644
--- a/tests/regressiontests/templates/loaders.py
+++ b/tests/regressiontests/templates/loaders.py
@@ -1,7 +1,5 @@
 """
 Test cases for the template loaders
-
-Note: This test requires setuptools!
 """
 
 from django.conf import settings
@@ -10,65 +8,27 @@ if __name__ == '__main__':
     settings.configure()
 
 import sys
-import pkg_resources
 import imp
 import StringIO
 import os.path
 
 from django.template import TemplateDoesNotExist, Context
-from django.template.loaders.eggs import Loader as EggLoader
+from django.template.loaders.app_directories import Loader as EggLoader
 from django.template import loader
 from django.utils import unittest
 
 
-# Mock classes and objects for pkg_resources functions.
-class MockProvider(pkg_resources.NullProvider):
-    def __init__(self, module):
-        pkg_resources.NullProvider.__init__(self, module)
-        self.module = module
-
-    def _has(self, path):
-        return path in self.module._resources
-
-    def _isdir(self,path):
-        return False
-
-    def get_resource_stream(self, manager, resource_name):
-        return self.module._resources[resource_name]
-
-    def _get(self, path):
-        return self.module._resources[path].read()
-
-class MockLoader(object):
-    pass
-
-def create_egg(name, resources):
-    """
-    Creates a mock egg with a list of resources.
-
-    name: The name of the module.
-    resources: A dictionary of resources. Keys are the names and values the data.
-    """
-    egg = imp.new_module(name)
-    egg.__loader__ = MockLoader()
-    egg._resources = resources
-    sys.modules[name] = egg
-
-
 class EggLoaderTest(unittest.TestCase):
     def setUp(self):
-        pkg_resources._provider_factories[MockLoader] = MockProvider
-
-        self.empty_egg = create_egg("egg_empty", {})
-        self.egg_1 = create_egg("egg_1", {
-            os.path.normcase('templates/y.html') : StringIO.StringIO("y"),
-            os.path.normcase('templates/x.txt') : StringIO.StringIO("x"),
-        })
-        self._old_installed_apps = settings.INSTALLED_APPS
-        settings.INSTALLED_APPS = []
+        self.old_path = sys.path[:]
+        self.old_apps = settings.INSTALLED_APPS
+        self.egg_dir = '%s/eggs' % os.path.dirname(__file__)
+        egg_name = '%s/templatesegg.egg' % self.egg_dir
+        sys.path.append(egg_name)
 
     def tearDown(self):
-        settings.INSTALLED_APPS = self._old_installed_apps
+        settings.INSTALLED_APPS = self.old_apps
+        sys.path = self.old_path
 
     def test_empty(self):
         "Loading any template on an empty egg should fail"
@@ -88,7 +48,7 @@ class EggLoaderTest(unittest.TestCase):
         egg_loader = EggLoader()
         contents, template_name = egg_loader.load_template_source("y.html")
         self.assertEqual(contents, "y")
-        self.assertEqual(template_name, "egg:egg_1:templates/y.html")
+        self.assertEqual(template_name, u"app:egg_1:templates/y.html")
 
     def test_not_installed(self):
         "Loading an existent template from an egg not included in INSTALLED_APPS should fail"
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index f74aa75..a13c157 100644
--- a/tests/regressiontests/templates/tests.py
+++ b/tests/regressiontests/templates/tests.py
@@ -39,14 +39,8 @@ from .nodelist import NodelistTest, ErrorIndexTest
 from .smartif import SmartIfTests
 from .response import (TemplateResponseTest, BaseTemplateResponseTest,
     CacheMiddlewareTest, SimpleTemplateResponseTest, CustomURLConfTest)
+from .loaders import RenderToStringTest, EggLoaderTest
 
-try:
-    from .loaders import RenderToStringTest, EggLoaderTest
-except ImportError, e:
-    if "pkg_resources" in e.message:
-        pass # If setuptools isn't installed, that's fine. Just move on.
-    else:
-        raise
 
 from . import filters
 
@@ -167,20 +161,16 @@ class Templates(unittest.TestCase):
         restore_warnings_state(self._warnings_state)
 
     def test_loaders_security(self):
-        ad_loader = app_directories.Loader()
-        fs_loader = filesystem.Loader()
         def test_template_sources(path, template_dirs, expected_sources):
             if isinstance(expected_sources, list):
                 # Fix expected sources so they are abspathed
                 expected_sources = [os.path.abspath(s) for s in expected_sources]
-            # Test the two loaders (app_directores and filesystem).
-            func1 = lambda p, t: list(ad_loader.get_template_sources(p, t))
-            func2 = lambda p, t: list(fs_loader.get_template_sources(p, t))
-            for func in (func1, func2):
-                if isinstance(expected_sources, list):
-                    self.assertEqual(func(path, template_dirs), expected_sources)
-                else:
-                    self.assertRaises(expected_sources, func, path, template_dirs)
+            # Test filesystem loader.
+            func = lambda p, t: list(filesystem.Loader(t).get_template_sources(p))
+            if isinstance(expected_sources, list):
+                self.assertEqual(func(path, template_dirs), expected_sources)
+            else:
+                self.assertRaises(expected_sources, func, path, template_dirs)
 
         template_dirs = ['/dir1', '/dir2']
         test_template_sources('index.html', template_dirs,
