Code

Ticket #596: pep-302.3.diff

File pep-302.3.diff, 46.4 KB (added by bhuztez, 2 years ago)

django.db.utils.load_backend

Line 
1diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
2index 8e83304..74bb558 100644
3--- a/django/core/management/__init__.py
4+++ b/django/core/management/__init__.py
5@@ -3,11 +3,12 @@ import os
6 import sys
7 from optparse import OptionParser, NO_DEFAULT
8 import imp
9+import pkgutil
10 import warnings
11 
12 from django.core.management.base import BaseCommand, CommandError, handle_default_options
13 from django.core.management.color import color_style
14-from django.utils.importlib import import_module
15+from django.utils.importlib import import_module, find_package_path
16 
17 # For backwards compatibility: get_version() used to be in this module.
18 from django import get_version
19@@ -23,11 +24,11 @@ def find_commands(management_dir):
20 
21     Returns an empty list if no commands are defined.
22     """
23-    command_dir = os.path.join(management_dir, 'commands')
24     try:
25-        return [f[:-3] for f in os.listdir(command_dir)
26-                if not f.startswith('_') and f.endswith('.py')]
27-    except OSError:
28+        commands_dir = find_package_path('commands', [management_dir])[0]
29+        return [name for loader,name,ispkg in pkgutil.iter_modules([commands_dir])
30+                if not name.startswith('_') ]
31+    except ImportError:
32         return []
33 
34 def find_management_module(app_name):
35@@ -39,26 +40,39 @@ def find_management_module(app_name):
36     """
37     parts = app_name.split('.')
38     parts.append('management')
39-    parts.reverse()
40-    part = parts.pop()
41-    path = None
42-
43-    # When using manage.py, the project module is added to the path,
44-    # loaded, then removed from the path. This means that
45-    # testproject.testapp.models can be loaded in future, even if
46-    # testproject isn't in the path. When looking for the management
47-    # module, we need look for the case where the project name is part
48-    # of the app_name but the project directory itself isn't on the path.
49-    try:
50-        f, path, descr = imp.find_module(part,path)
51-    except ImportError,e:
52-        if os.path.basename(os.getcwd()) != part:
53-            raise e
54+
55+    for i in range(len(parts), 0, -1):
56+        try:
57+            path = sys.modules['.'.join(parts[:i])].__path__
58+        except AttributeError:
59+            raise ImportError("No package named %s" % parts[i-1])
60+        except KeyError:
61+            continue
62+
63+        parts = parts[i:]
64+        parts.reverse()
65+        break
66+    else:
67+        parts.reverse()
68+        part = parts.pop()
69+        path = None
70+
71+        # When using manage.py, the project module is added to the path,
72+        # loaded, then removed from the path. This means that
73+        # testproject.testapp.models can be loaded in future, even if
74+        # testproject isn't in the path. When looking for the management
75+        # module, we need look for the case where the project name is part
76+        # of the app_name but the project directory itself isn't on the path.
77+        try:
78+            path = find_package_path(part, path)
79+        except ImportError,e:
80+            if os.path.basename(os.getcwd()) != part:
81+                raise e
82 
83     while parts:
84         part = parts.pop()
85-        f, path, descr = imp.find_module(part, path and [path] or None)
86-    return path
87+        path = find_package_path(part, path)
88+    return path[0]
89 
90 def load_command_class(app_name, name):
91     """
92diff --git a/django/db/utils.py b/django/db/utils.py
93index 3f5b86e..5c4740f 100644
94--- a/django/db/utils.py
95+++ b/django/db/utils.py
96@@ -1,5 +1,6 @@
97 import os
98 from threading import local
99+import pkgutil
100 
101 from django.conf import settings
102 from django.core.exceptions import ImproperlyConfigured
103@@ -25,13 +26,10 @@ def load_backend(backend_name):
104     except ImportError, e_user:
105         # The database backend wasn't found. Display a helpful error message
106         # listing all possible (built-in) database backends.
107-        backend_dir = os.path.join(os.path.dirname(__file__), 'backends')
108-        try:
109-            available_backends = [f for f in os.listdir(backend_dir)
110-                    if os.path.isdir(os.path.join(backend_dir, f))
111-                    and not f.startswith('.')]
112-        except EnvironmentError:
113-            available_backends = []
114+        backend_path = import_module('django.db.backends').__path__
115+        available_backends = [ name for loader, name, ispkg
116+                in pkgutil.iter_modules(backend_path)
117+                if ispkg ]
118         full_notation = backend_name.startswith('django.db.backends.')
119         if full_notation:
120             backend_name = backend_name[19:] # See #15621.
121diff --git a/django/template/loader.py b/django/template/loader.py
122index 4185017..98ea96c 100644
123--- a/django/template/loader.py
124+++ b/django/template/loader.py
125@@ -3,10 +3,9 @@
126 # This uses the TEMPLATE_LOADERS setting, which is a list of loaders to use.
127 # Each loader is expected to have this interface:
128 #
129-#    callable(name, dirs=[])
130+#    callable(name)
131 #
132 # name is the template name.
133-# dirs is an optional list of directories to search instead of TEMPLATE_DIRS.
134 #
135 # The loader should return a tuple of (template_source, path). The path returned
136 # might be shown to the user for debugging purposes, so it should identify where
137@@ -38,12 +37,12 @@ class BaseLoader(object):
138     def __init__(self, *args, **kwargs):
139         pass
140 
141-    def __call__(self, template_name, template_dirs=None):
142-        return self.load_template(template_name, template_dirs)
143+    def __call__(self, template_name):
144+        return self.load_template(template_name)
145 
146-    def load_template(self, template_name, template_dirs=None):
147-        source, display_name = self.load_template_source(template_name, template_dirs)
148-        origin = make_origin(display_name, self.load_template_source, template_name, template_dirs)
149+    def load_template(self, template_name):
150+        source, display_name = self.load_template_source(template_name)
151+        origin = make_origin(display_name, self.load_template_source, template_name)
152         try:
153             template = get_template_from_string(source, origin, template_name)
154             return template, None
155@@ -54,7 +53,7 @@ class BaseLoader(object):
156             # not exist.
157             return source, display_name
158 
159-    def load_template_source(self, template_name, template_dirs=None):
160+    def load_template_source(self, template_name):
161         """
162         Returns a tuple containing the source and origin for the given template
163         name.
164@@ -71,16 +70,16 @@ class BaseLoader(object):
165         pass
166 
167 class LoaderOrigin(Origin):
168-    def __init__(self, display_name, loader, name, dirs):
169+    def __init__(self, display_name, loader, name):
170         super(LoaderOrigin, self).__init__(display_name)
171-        self.loader, self.loadname, self.dirs = loader, name, dirs
172+        self.loader, self.loadname = loader, name
173 
174     def reload(self):
175-        return self.loader(self.loadname, self.dirs)[0]
176+        return self.loader(self.loadname)[0]
177 
178-def make_origin(display_name, loader, name, dirs):
179+def make_origin(display_name, loader, name):
180     if settings.TEMPLATE_DEBUG and display_name:
181-        return LoaderOrigin(display_name, loader, name, dirs)
182+        return LoaderOrigin(display_name, loader, name)
183     else:
184         return None
185 
186@@ -117,7 +116,7 @@ def find_template_loader(loader):
187     else:
188         raise ImproperlyConfigured('Loader does not define a "load_template" callable template source loader')
189 
190-def find_template(name, dirs=None):
191+def find_template(name):
192     # Calculate template_source_loaders the first time the function is executed
193     # because putting this logic in the module-level namespace may cause
194     # circular import errors. See Django ticket #1292.
195@@ -131,8 +130,8 @@ def find_template(name, dirs=None):
196         template_source_loaders = tuple(loaders)
197     for loader in template_source_loaders:
198         try:
199-            source, display_name = loader(name, dirs)
200-            return (source, make_origin(display_name, loader, name, dirs))
201+            source, display_name = loader(name)
202+            return (source, make_origin(display_name, loader, name))
203         except TemplateDoesNotExist:
204             pass
205     raise TemplateDoesNotExist(name)
206diff --git a/django/template/loaders/app_directories.py b/django/template/loaders/app_directories.py
207index b0560b4..2db1a47 100644
208--- a/django/template/loaders/app_directories.py
209+++ b/django/template/loaders/app_directories.py
210@@ -3,62 +3,27 @@ Wrapper for loading templates from "templates" directories in INSTALLED_APPS
211 packages.
212 """
213 
214-import os
215-import sys
216+import pkgutil
217 
218 from django.conf import settings
219-from django.core.exceptions import ImproperlyConfigured
220 from django.template.base import TemplateDoesNotExist
221 from django.template.loader import BaseLoader
222 from django.utils._os import safe_join
223-from django.utils.importlib import import_module
224 
225-# At compile time, cache the directories to search.
226-fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
227-app_template_dirs = []
228-for app in settings.INSTALLED_APPS:
229-    try:
230-        mod = import_module(app)
231-    except ImportError, e:
232-        raise ImproperlyConfigured('ImportError %s: %s' % (app, e.args[0]))
233-    template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates')
234-    if os.path.isdir(template_dir):
235-        app_template_dirs.append(template_dir.decode(fs_encoding))
236-
237-# It won't change, so convert it to a tuple to save memory.
238-app_template_dirs = tuple(app_template_dirs)
239 
240 class Loader(BaseLoader):
241     is_usable = True
242 
243-    def get_template_sources(self, template_name, template_dirs=None):
244-        """
245-        Returns the absolute paths to "template_name", when appended to each
246-        directory in "template_dirs". Any paths that don't lie inside one of the
247-        template dirs are excluded from the result set, for security reasons.
248-        """
249-        if not template_dirs:
250-            template_dirs = app_template_dirs
251-        for template_dir in template_dirs:
252+    def load_template_source(self, template_name):
253+        for app in settings.INSTALLED_APPS:
254+            resource = safe_join('/templates', template_name)[1:]
255             try:
256-                yield safe_join(template_dir, template_name)
257-            except UnicodeDecodeError:
258-                # The template dir name was a bytestring that wasn't valid UTF-8.
259-                raise
260-            except ValueError:
261-                # The joined path was located outside of template_dir.
262+                data = pkgutil.get_data(app, resource)
263+                if data is not None:
264+                    return data, 'app:' + app + ':'+resource
265+            except Exception:
266                 pass
267 
268-    def load_template_source(self, template_name, template_dirs=None):
269-        for filepath in self.get_template_sources(template_name, template_dirs):
270-            try:
271-                file = open(filepath)
272-                try:
273-                    return (file.read().decode(settings.FILE_CHARSET), filepath)
274-                finally:
275-                    file.close()
276-            except IOError:
277-                pass
278         raise TemplateDoesNotExist(template_name)
279 
280 _loader = Loader()
281diff --git a/django/template/loaders/cached.py b/django/template/loaders/cached.py
282index 4c25acd..eeb1e6e 100644
283--- a/django/template/loaders/cached.py
284+++ b/django/template/loaders/cached.py
285@@ -27,23 +27,18 @@ class Loader(BaseLoader):
286             self._cached_loaders = cached_loaders
287         return self._cached_loaders
288 
289-    def find_template(self, name, dirs=None):
290+    def find_template(self, name):
291         for loader in self.loaders:
292             try:
293-                template, display_name = loader(name, dirs)
294-                return (template, make_origin(display_name, loader, name, dirs))
295+                template, display_name = loader(name)
296+                return (template, make_origin(display_name, loader, name))
297             except TemplateDoesNotExist:
298                 pass
299         raise TemplateDoesNotExist(name)
300 
301-    def load_template(self, template_name, template_dirs=None):
302-        key = template_name
303-        if template_dirs:
304-            # If template directories were specified, use a hash to differentiate
305-            key = '-'.join([template_name, hashlib.sha1('|'.join(template_dirs)).hexdigest()])
306-
307-        if key not in self.template_cache:
308-            template, origin = self.find_template(template_name, template_dirs)
309+    def load_template(self, template_name):
310+        if template_name not in self.template_cache:
311+            template, origin = self.find_template(template_name)
312             if not hasattr(template, 'render'):
313                 try:
314                     template = get_template_from_string(template, origin, template_name)
315@@ -53,8 +48,8 @@ class Loader(BaseLoader):
316                     # we were asked to load. This allows for correct identification (later)
317                     # of the actual template that does not exist.
318                     return template, origin
319-            self.template_cache[key] = template
320-        return self.template_cache[key], None
321+            self.template_cache[template_name] = template
322+        return self.template_cache[template_name], None
323 
324     def reset(self):
325         "Empty the template cache."
326diff --git a/django/template/loaders/eggs.py b/django/template/loaders/eggs.py
327deleted file mode 100644
328index 42f87a4..0000000
329--- a/django/template/loaders/eggs.py
330+++ /dev/null
331@@ -1,30 +0,0 @@
332-# Wrapper for loading templates from eggs via pkg_resources.resource_string.
333-
334-try:
335-    from pkg_resources import resource_string
336-except ImportError:
337-    resource_string = None
338-
339-from django.template.base import TemplateDoesNotExist
340-from django.template.loader import BaseLoader
341-from django.conf import settings
342-
343-class Loader(BaseLoader):
344-    is_usable = resource_string is not None
345-
346-    def load_template_source(self, template_name, template_dirs=None):
347-        """
348-        Loads templates from Python eggs via pkg_resource.resource_string.
349-
350-        For every installed app, it tries to get the resource (app, template_name).
351-        """
352-        if resource_string is not None:
353-            pkg_name = 'templates/' + template_name
354-            for app in settings.INSTALLED_APPS:
355-                try:
356-                    return (resource_string(app, pkg_name).decode(settings.FILE_CHARSET), 'egg:%s:%s' % (app, pkg_name))
357-                except:
358-                    pass
359-        raise TemplateDoesNotExist(template_name)
360-
361-_loader = Loader()
362diff --git a/django/template/loaders/filesystem.py b/django/template/loaders/filesystem.py
363index 51025ac..b926c6b 100644
364--- a/django/template/loaders/filesystem.py
365+++ b/django/template/loaders/filesystem.py
366@@ -10,15 +10,16 @@ from django.utils._os import safe_join
367 class Loader(BaseLoader):
368     is_usable = True
369 
370-    def get_template_sources(self, template_name, template_dirs=None):
371+    def __init__(self, template_dirs=None):
372+        self.template_dirs = template_dirs or settings.TEMPLATE_DIRS
373+
374+    def get_template_sources(self, template_name):
375         """
376         Returns the absolute paths to "template_name", when appended to each
377         directory in "template_dirs". Any paths that don't lie inside one of the
378         template dirs are excluded from the result set, for security reasons.
379         """
380-        if not template_dirs:
381-            template_dirs = settings.TEMPLATE_DIRS
382-        for template_dir in template_dirs:
383+        for template_dir in self.template_dirs:
384             try:
385                 yield safe_join(template_dir, template_name)
386             except UnicodeDecodeError:
387@@ -30,9 +31,9 @@ class Loader(BaseLoader):
388                 # fatal).
389                 pass
390 
391-    def load_template_source(self, template_name, template_dirs=None):
392+    def load_template_source(self, template_name):
393         tried = []
394-        for filepath in self.get_template_sources(template_name, template_dirs):
395+        for filepath in self.get_template_sources(template_name):
396             try:
397                 file = open(filepath)
398                 try:
399diff --git a/django/utils/importlib.py b/django/utils/importlib.py
400index ef4d0e4..f53abd9 100644
401--- a/django/utils/importlib.py
402+++ b/django/utils/importlib.py
403@@ -1,5 +1,9 @@
404 # Taken from Python 2.7 with permission from/by the original author.
405+import os
406 import sys
407+import imp
408+import pkgutil
409+import warnings
410 
411 def _resolve_name(name, package, level):
412     """Return the absolute name of the module to be imported."""
413@@ -34,3 +38,86 @@ def import_module(name, package=None):
414         name = _resolve_name(name[level:], package, level)
415     __import__(name)
416     return sys.modules[name]
417+
418+
419+def find_package_path(name, path=None):
420+    """Finds search path for package with given name.
421+
422+    The 'path' argument defaults to ``sys.path``.
423+
424+    Raises ImportError if no search path could be found.
425+    """
426+    if path is None:
427+        path = sys.path
428+
429+    results = []
430+
431+    for path_item in path:
432+        importer = get_importer(path_item)
433+
434+        if importer is None:
435+            continue
436+
437+        try:
438+            loader = importer.find_module(name)
439+
440+            if loader is not None:
441+
442+                if not hasattr(loader, 'is_package'):
443+                    warnings.warn(
444+                        "Django cannot find search path for package '%s' ",
445+                        "under '%s', because the loader returned by '%s' does ",
446+                        "not implement 'is_package' method."%(
447+                            name,
448+                            path_item,
449+                            importer.__class__.__name__))
450+                    continue
451+
452+                if not hasattr(loader, 'get_filename'):
453+                    warnings.warn(
454+                        "Django cannot find search path for package '%s' ",
455+                        "under '%s', because the loader returned by '%s' does ",
456+                        "not implement 'get_filename' method."%(
457+                            name,
458+                            path_item,
459+                            importer.__class__.__name__))
460+                    continue
461+
462+                if loader.is_package(name):
463+                    results.append(os.path.dirname(loader.get_filename(name)))
464+        except ImportError:
465+            pass
466+
467+    if not results:
468+        raise ImportError("No package named %s" % name)
469+
470+    return results
471+
472+
473+get_importer = pkgutil.get_importer
474+
475+try:
476+    import zipimport
477+
478+    if hasattr(zipimport.zipimporter, 'get_filename'):
479+        class ZipImporter(zipimport.zipimporter):
480+            def get_filename(self, fullname):
481+                archivepath = os.path.join(self.archive, self.prefix)
482+                if self.is_package(fullname):
483+                    return os.path.join(archivepath, fullname, '__init__.py')
484+
485+                return os.path.join(archivepath, fullname + '.py')
486+
487+        def get_importer(path_item):
488+            importer = pkgutil.get_importer(path_item)
489+
490+            if isinstance(importer, zipimport.zipimporter):
491+                archivepath = os.path.join(importer.archive, importer.prefix)
492+                importer = ZipImporter(os.path.dirname(archivepath))
493+
494+            return importer
495+
496+except ImportError:
497+    pass
498+
499+
500diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
501index 82072b1..115f964 100644
502--- a/django/utils/translation/trans_real.py
503+++ b/django/utils/translation/trans_real.py
504@@ -6,6 +6,8 @@ import re
505 import sys
506 import gettext as gettext_module
507 from threading import local
508+import pkgutil
509+import copy
510 
511 try:
512     from cStringIO import StringIO
513@@ -111,13 +113,6 @@ def translation(language):
514 
515     globalpath = os.path.join(os.path.dirname(sys.modules[settings.__module__].__file__), 'locale')
516 
517-    if settings.SETTINGS_MODULE is not None:
518-        parts = settings.SETTINGS_MODULE.split('.')
519-        project = import_module(parts[0])
520-        projectpath = os.path.join(os.path.dirname(project.__file__), 'locale')
521-    else:
522-        projectpath = None
523-
524     def _fetch(lang, fallback=None):
525 
526         global _translations
527@@ -128,13 +123,30 @@ def translation(language):
528 
529         loc = to_locale(lang)
530 
531-        def _translation(path):
532-            try:
533-                t = gettext_module.translation('django', path, [loc], DjangoTranslation)
534-                t.set_language(lang)
535-                return t
536-            except IOError:
537-                return None
538+        def _translation(path_or_appname, is_appname=False):
539+            if is_appname:
540+                nelangs = gettext_module._expand_lang(loc)
541+                for nelang in nelangs:
542+                    locpath = os.path.join('locale', nelang, 'LC_MESSAGES', 'django.mo')
543+                    try:
544+                        data = pkgutil.get_data(path_or_appname, locpath)
545+                    except:
546+                        continue
547+
548+                    if data is not None:
549+                        t = DjangoTranslation(StringIO(data))
550+                        t = copy.copy(t)
551+                        break
552+                else:
553+                    return None
554+            else:
555+                try:
556+                    t = gettext_module.translation('django', path_or_appname, [loc], DjangoTranslation)
557+                except IOError:
558+                    return None
559+
560+            t.set_language(lang)
561+            return t
562 
563         res = _translation(globalpath)
564 
565@@ -147,8 +159,8 @@ def translation(language):
566             res._info = res._info.copy()
567             res._catalog = res._catalog.copy()
568 
569-        def _merge(path):
570-            t = _translation(path)
571+        def _merge(path_or_appname, is_appname=False):
572+            t = _translation(path_or_appname, is_appname)
573             if t is not None:
574                 if res is None:
575                     return t
576@@ -157,16 +169,9 @@ def translation(language):
577             return res
578 
579         for appname in reversed(settings.INSTALLED_APPS):
580-            app = import_module(appname)
581-            apppath = os.path.join(os.path.dirname(app.__file__), 'locale')
582-
583-            if os.path.isdir(apppath):
584-                res = _merge(apppath)
585+            res = _merge(appname, is_appname=True)
586 
587-        localepaths = [os.path.normpath(path) for path in settings.LOCALE_PATHS]
588-        if (projectpath and os.path.isdir(projectpath) and
589-                os.path.normpath(projectpath) not in localepaths):
590-            res = _merge(projectpath)
591+        res = _merge(settings.SETTINGS_MODULE, is_appname=True)
592 
593         for localepath in reversed(settings.LOCALE_PATHS):
594             if os.path.isdir(localepath):
595diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
596index 03fef1d..8154d2c 100644
597--- a/docs/ref/templates/api.txt
598+++ b/docs/ref/templates/api.txt
599@@ -655,9 +655,9 @@ class. Here are the template loaders that come with Django:
600     This loader is enabled by default.
601 
602 ``django.template.loaders.app_directories.Loader``
603-    Loads templates from Django apps on the filesystem. For each app in
604-    :setting:`INSTALLED_APPS`, the loader looks for a ``templates``
605-    subdirectory. If the directory exists, Django looks for templates in there.
606+    Loads templates from Django apps. For each app in :setting:`INSTALLED_APPS`,
607+    the loader looks for a ``templates`` subdirectory. If the directory exists,
608+    Django looks for templates in there.
609 
610     This means you can store templates with your individual apps. This also
611     makes it easy to distribute Django apps with default templates.
612@@ -672,18 +672,8 @@ class. Here are the template loaders that come with Django:
613     * ``/path/to/myproject/polls/templates/foo.html``
614     * ``/path/to/myproject/music/templates/foo.html``
615 
616-    Note that the loader performs an optimization when it is first imported: It
617-    caches a list of which :setting:`INSTALLED_APPS` packages have a
618-    ``templates`` subdirectory.
619-
620     This loader is enabled by default.
621 
622-``django.template.loaders.eggs.Loader``
623-    Just like ``app_directories`` above, but it loads templates from Python
624-    eggs rather than from the filesystem.
625-
626-    This loader is disabled by default.
627-
628 ``django.template.loaders.cached.Loader``
629     By default, the templating system will read and compile your templates every
630     time they need to be rendered. While the Django templating system is quite
631@@ -838,8 +828,8 @@ of the ``load_template_source()`` method implemented there::
632     class Loader(app_directories.Loader):
633         is_usable = True
634 
635-        def load_template(self, template_name, template_dirs=None):
636-            source, origin = self.load_template_source(template_name, template_dirs)
637+        def load_template(self, template_name):
638+            source, origin = self.load_template_source(template_name)
639             template = Template(source)
640             return template, origin
641 
642diff --git a/tests/regressiontests/admin_scripts/lib1/nons_app/__init__.py b/tests/regressiontests/admin_scripts/lib1/nons_app/__init__.py
643new file mode 100644
644index 0000000..e69de29
645diff --git a/tests/regressiontests/admin_scripts/lib1/nons_app/management/__init__.py b/tests/regressiontests/admin_scripts/lib1/nons_app/management/__init__.py
646new file mode 100644
647index 0000000..e69de29
648diff --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
649new file mode 100644
650index 0000000..e69de29
651diff --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
652new file mode 100644
653index 0000000..a393663
654--- /dev/null
655+++ b/tests/regressiontests/admin_scripts/lib1/nons_app/management/commands/nons_app_command1.py
656@@ -0,0 +1,9 @@
657+from django.core.management.base import BaseCommand
658+
659+class Command(BaseCommand):
660+    help = 'Test managment commands in non-namespaced app'
661+    requires_model_validation = False
662+    args = ''
663+
664+    def handle(self, *labels, **options):
665+        print 'EXECUTE:nons_app_command1'
666diff --git a/tests/regressiontests/admin_scripts/lib1/nons_app/models.py b/tests/regressiontests/admin_scripts/lib1/nons_app/models.py
667new file mode 100644
668index 0000000..e69de29
669diff --git a/tests/regressiontests/admin_scripts/lib1/npapp/__init__.py b/tests/regressiontests/admin_scripts/lib1/npapp/__init__.py
670new file mode 100644
671index 0000000..e69de29
672diff --git a/tests/regressiontests/admin_scripts/lib1/npapp/management.py b/tests/regressiontests/admin_scripts/lib1/npapp/management.py
673new file mode 100644
674index 0000000..e69de29
675diff --git a/tests/regressiontests/admin_scripts/lib1/npapp/models.py b/tests/regressiontests/admin_scripts/lib1/npapp/models.py
676new file mode 100644
677index 0000000..e69de29
678diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/__init__.py b/tests/regressiontests/admin_scripts/lib1/nsapps/__init__.py
679new file mode 100644
680index 0000000..32f26d8
681--- /dev/null
682+++ b/tests/regressiontests/admin_scripts/lib1/nsapps/__init__.py
683@@ -0,0 +1,6 @@
684+# http://packages.python.org/distribute/setuptools.html#namespace-packages
685+try:
686+    __import__('pkg_resources').declare_namespace(__name__)
687+except ImportError:
688+    from pkgutil import extend_path
689+    __path__ = extend_path(__path__, __name__)
690diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/__init__.py b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/__init__.py
691new file mode 100644
692index 0000000..32f26d8
693--- /dev/null
694+++ b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/__init__.py
695@@ -0,0 +1,6 @@
696+# http://packages.python.org/distribute/setuptools.html#namespace-packages
697+try:
698+    __import__('pkg_resources').declare_namespace(__name__)
699+except ImportError:
700+    from pkgutil import extend_path
701+    __path__ = extend_path(__path__, __name__)
702diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/__init__.py b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/__init__.py
703new file mode 100644
704index 0000000..e69de29
705diff --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
706new file mode 100644
707index 0000000..e69de29
708diff --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
709new file mode 100644
710index 0000000..e69de29
711diff --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
712new file mode 100644
713index 0000000..2f479bb
714--- /dev/null
715+++ b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/management/commands/app1_command1.py
716@@ -0,0 +1,9 @@
717+from django.core.management.base import BaseCommand
718+
719+class Command(BaseCommand):
720+    help = 'Test managment commands in namespaced apps'
721+    requires_model_validation = False
722+    args = ''
723+
724+    def handle(self, *labels, **options):
725+        print 'EXECUTE:app1_command1'
726diff --git a/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/models.py b/tests/regressiontests/admin_scripts/lib1/nsapps/contrib/app1/models.py
727new file mode 100644
728index 0000000..e69de29
729diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/__init__.py b/tests/regressiontests/admin_scripts/lib2/nsapps/__init__.py
730new file mode 100644
731index 0000000..32f26d8
732--- /dev/null
733+++ b/tests/regressiontests/admin_scripts/lib2/nsapps/__init__.py
734@@ -0,0 +1,6 @@
735+# http://packages.python.org/distribute/setuptools.html#namespace-packages
736+try:
737+    __import__('pkg_resources').declare_namespace(__name__)
738+except ImportError:
739+    from pkgutil import extend_path
740+    __path__ = extend_path(__path__, __name__)
741diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/__init__.py b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/__init__.py
742new file mode 100644
743index 0000000..32f26d8
744--- /dev/null
745+++ b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/__init__.py
746@@ -0,0 +1,6 @@
747+# http://packages.python.org/distribute/setuptools.html#namespace-packages
748+try:
749+    __import__('pkg_resources').declare_namespace(__name__)
750+except ImportError:
751+    from pkgutil import extend_path
752+    __path__ = extend_path(__path__, __name__)
753diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/__init__.py b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/__init__.py
754new file mode 100644
755index 0000000..e69de29
756diff --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
757new file mode 100644
758index 0000000..e69de29
759diff --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
760new file mode 100644
761index 0000000..e69de29
762diff --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
763new file mode 100644
764index 0000000..b9e20a7
765--- /dev/null
766+++ b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/management/commands/app2_command1.py
767@@ -0,0 +1,9 @@
768+from django.core.management.base import BaseCommand
769+
770+class Command(BaseCommand):
771+    help = 'Test managment commands in namespaced apps'
772+    requires_model_validation = False
773+    args = ''
774+
775+    def handle(self, *labels, **options):
776+        print 'EXECUTE:app2_command1'
777diff --git a/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/models.py b/tests/regressiontests/admin_scripts/lib2/nsapps/contrib/app2/models.py
778new file mode 100644
779index 0000000..e69de29
780diff --git a/tests/regressiontests/admin_scripts/lib3/_addsitedir.py b/tests/regressiontests/admin_scripts/lib3/_addsitedir.py
781new file mode 100644
782index 0000000..9e264d2
783--- /dev/null
784+++ b/tests/regressiontests/admin_scripts/lib3/_addsitedir.py
785@@ -0,0 +1 @@
786+import os.path, site; site.addsitedir(os.path.dirname(__file__))
787diff --git a/tests/regressiontests/admin_scripts/lib3/egg_module.pth b/tests/regressiontests/admin_scripts/lib3/egg_module.pth
788new file mode 100644
789index 0000000..9367ab5
790--- /dev/null
791+++ b/tests/regressiontests/admin_scripts/lib3/egg_module.pth
792@@ -0,0 +1 @@
793+test_egg.egg
794diff --git a/tests/regressiontests/admin_scripts/lib3/exapps-nspkg.pth b/tests/regressiontests/admin_scripts/lib3/exapps-nspkg.pth
795new file mode 100644
796index 0000000..1f31155
797--- /dev/null
798+++ b/tests/regressiontests/admin_scripts/lib3/exapps-nspkg.pth
799@@ -0,0 +1 @@
800+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)
801diff --git a/tests/regressiontests/admin_scripts/lib3/exapps/app3/__init__.py b/tests/regressiontests/admin_scripts/lib3/exapps/app3/__init__.py
802new file mode 100644
803index 0000000..e69de29
804diff --git a/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/__init__.py b/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/__init__.py
805new file mode 100644
806index 0000000..e69de29
807diff --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
808new file mode 100644
809index 0000000..e69de29
810diff --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
811new file mode 100644
812index 0000000..97f5d33
813--- /dev/null
814+++ b/tests/regressiontests/admin_scripts/lib3/exapps/app3/management/commands/app3_command1.py
815@@ -0,0 +1,9 @@
816+from django.core.management.base import BaseCommand
817+
818+class Command(BaseCommand):
819+    help = 'Test managment commands in namespaced apps'
820+    requires_model_validation = False
821+    args = ''
822+
823+    def handle(self, *labels, **options):
824+        print 'EXECUTE:app3_command1'
825diff --git a/tests/regressiontests/admin_scripts/lib3/exapps/app3/models.py b/tests/regressiontests/admin_scripts/lib3/exapps/app3/models.py
826new file mode 100644
827index 0000000..e69de29
828diff --git a/tests/regressiontests/admin_scripts/lib3/test_egg.egg b/tests/regressiontests/admin_scripts/lib3/test_egg.egg
829new file mode 100644
830index 0000000000000000000000000000000000000000..d9e57de006a3d602515293f8e980bf3a16fb42c0
831GIT binary patch
832literal 2210
833zcmWIWW@Zs#W&na+g#z{<8U{Fl3|Dt|T~9wZfBgWcG7g3{KxHDAuKle5O78$-K~!ZB
834z^|5C+avd@dV0&QeKT+IcWwzNt$AHBOuWGiW^E|0~S|nLhZ9Ow6Z`b?h&-X7l#KHBh
835zGf2q)-n(7*SQNg9C6^pYKAZ6`^S*BSyQv&cUcXhIbLgw+nTectc?6~3uC9yNw%@sF
836z%ItZU8-gRR@<p(DZr01@&6oUg*2%XH)tT;p3*R&VooCL-z#xL`%wYe}AZOQLy^@NO
837zseK1QE_HeT&--$}fT-Y_2pj#SlFkL2Ia9R1z3&YW$hEDwHMjD;fuxnn<YS_977M&R
838zu%dHMh3c<Wrx~B0zcgk0r=s4kFE_0Ic06}8$L(iDarse;`D34maV9DL^?37iT78$4
839zu;IH0CoB42FDd2_n0t1<bS;nS%|HFW4h3s`69&1M3mpESfSt^C-3aJd1`w7-c5zB-
840zL26z~YF=_>d`@Owb}`85T&Q|ip0Nz)2I>J}F=V|Z`33Pgsb#4-AWf<1>G8SwDWy57
841zXxfpjMv2p^%mUrw#59O{NK!eBmQ+AiA`Av67Koo#6`-amkh_o+#>Z#oWtPOp>lIYO
842zVvd0U-EcHLxrup+>8ZJ?c_m2p+{#0>M-kN?Bt1k~DUVZoa(*t*u#{pvc54yVjKvWg
843z3_F2gHQm(j`*xsy9$*5{C2S5TD4{L_2BB}CcONJzf46gee`Y}-UxUeP$C<(gLc3RV
844zY9Cwi_n@qWz2AwZxYCuY=4Gw2oV2^}(@yDPS8>aY?k=--b8BlHne^Ic|6BWKH)7Jy
845zXsq#?eWx}ep56KFx(QD9DgGB`hCMj6_@itPSErDB#zVor9U@z^*FXBlA!>Exjl$u{
846zsuuH{{dm6}Ulb7>vsbSqJM5*w#jS~~)~!DGw}|g^*kb!TX4*Er&D*q1x2SHj|9<>`
847zaDBt~!)B*vi6f<AwA2F1vq-50m~2yXiot1xkx7IZcc}%`1_S~P2OL2(QW*x*hP@O6
848zDP~|$XxP%I4y2K^LCUlMZ&dB*r3+X$So=9-?MP(}#01>A9brNPF#h2Vz?S#XjY7}-
849z2&48O8--F7pqqhS0wB!zjcf+2JV1m8W}XEV2oL~@1#Kpjcto}rTLA&l2#SXgRE;Rv
850z1{N8ZmV*im2mo2$focX)QGo0YYy}9!43Ina;536sCxHqS2mm?hH%{Y_iWiXoAV~$?
851zZJ+`M0zhuF09GEznFLWh!VSafNbCg;!rTVJ=Asrq$icY=OHM`@-Nb_GWJJDZWdo_=
852P1Hv0X>$d>aF)#oC`tnrE
853
854literal 0
855HcmV?d00001
856
857diff --git a/tests/regressiontests/admin_scripts/tests.py b/tests/regressiontests/admin_scripts/tests.py
858index 669c6e8..6408b97 100644
859--- a/tests/regressiontests/admin_scripts/tests.py
860+++ b/tests/regressiontests/admin_scripts/tests.py
861@@ -91,6 +91,10 @@ class AdminScriptTestCase(unittest.TestCase):
862     def run_test(self, script, args, settings_file=None, apps=None):
863         project_dir = os.path.dirname(test_dir)
864         base_dir = os.path.dirname(project_dir)
865+        lib1_dir = os.path.join(os.path.dirname(__file__), 'lib1')
866+        lib2_dir = os.path.join(os.path.dirname(__file__), 'lib2')
867+        lib3_dir = os.path.join(os.path.dirname(__file__), 'lib3')
868+        eggs_dir = os.path.join(os.path.dirname(__file__), 'eggs')
869         ext_backend_base_dirs = self._ext_backend_paths()
870 
871         # Remember the old environment
872@@ -108,7 +112,7 @@ class AdminScriptTestCase(unittest.TestCase):
873             os.environ['DJANGO_SETTINGS_MODULE'] = settings_file
874         elif 'DJANGO_SETTINGS_MODULE' in os.environ:
875             del os.environ['DJANGO_SETTINGS_MODULE']
876-        python_path = [project_dir, base_dir]
877+        python_path = [project_dir, base_dir, lib1_dir, lib2_dir, lib3_dir]
878         python_path.extend(ext_backend_base_dirs)
879         os.environ[python_path_var_name] = os.pathsep.join(python_path)
880 
881@@ -1563,3 +1567,95 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
882         self.assertOutput(err, "Destination directory '%s' does not exist, please create it first." % testproject_dir)
883         self.assertFalse(os.path.exists(testproject_dir))
884 
885+
886+class NamespacePackagedApps(AdminScriptTestCase):
887+    def setUp(self):
888+        self.write_settings('settings.py', apps=['nons_app', 'nsapps.contrib.app1','nsapps.contrib.app2','exapps.app3', 'egg_module'])
889+        settings_file = open(os.path.join(test_dir, 'settings.py'), 'a')
890+        settings_file.write('import _addsitedir')
891+        settings_file.close()
892+       
893+    def tearDown(self):
894+        self.remove_settings('settings.py')
895+
896+    def test_help(self):
897+        out, err = self.run_manage(['help'])
898+        self.assertNoOutput(err)
899+        self.assertOutput(out, "nons_app_command1")
900+        self.assertOutput(out, "app1_command1")
901+        self.assertOutput(out, "app2_command1")
902+        self.assertOutput(out, "app3_command1")
903+        self.assertOutput(out, "egg_command")
904+
905+    def test_nons_app(self):
906+        args = ['nons_app_command1']
907+        out, err = self.run_manage(args)
908+        self.assertNoOutput(err)
909+        self.assertOutput(out, "EXECUTE:nons_app_command1")
910+
911+    def test_nsapps(self):
912+        args = ['app1_command1']
913+        out, err = self.run_manage(args)
914+        self.assertNoOutput(err)
915+        self.assertOutput(out, "EXECUTE:app1_command1")
916+
917+        args = ['app2_command1']
918+        out, err = self.run_manage(args)
919+        self.assertNoOutput(err)
920+        self.assertOutput(out, "EXECUTE:app2_command1")
921+
922+    def test_exapps(self):
923+        args = ['app3_command1']
924+        out, err = self.run_manage(args)
925+        self.assertNoOutput(err)
926+        self.assertOutput(out, "EXECUTE:app3_command1")
927+
928+    def test_exapps(self):
929+        args = ['egg_command']
930+        out, err = self.run_manage(args)
931+        self.assertNoOutput(err)
932+        self.assertOutput(out, "EXECUTE:egg_command")
933+
934+
935+class PreloadedNamespacePackagedApps(AdminScriptTestCase):
936+    def setUp(self):
937+        self.write_settings('settings.py', apps=['nsapps.contrib.app1','nsapps.contrib.app2'])
938+        settings_file = open(os.path.join(test_dir, 'settings.py'), 'a')
939+        settings_file.write('import nsapps')
940+        settings_file.close()
941+       
942+    def tearDown(self):
943+        self.remove_settings('settings.py')
944+
945+    def test_help(self):
946+        out, err = self.run_manage(['help'])
947+        self.assertNoOutput(err)
948+        self.assertOutput(out, "app1_command1")
949+        self.assertOutput(out, "app2_command1")
950+
951+    def test_nsapps(self):
952+        args = ['app1_command1']
953+        out, err = self.run_manage(args)
954+        self.assertNoOutput(err)
955+        self.assertOutput(out, "EXECUTE:app1_command1")
956+
957+        args = ['app2_command1']
958+        out, err = self.run_manage(args)
959+        self.assertNoOutput(err)
960+        self.assertOutput(out, "EXECUTE:app2_command1")
961+
962+
963+class NonPackageManagementApps(AdminScriptTestCase):
964+    def setUp(self):
965+        self.write_settings('settings.py', apps=['npapp'])
966+        settings_file = open(os.path.join(test_dir, 'settings.py'), 'a')
967+        settings_file.write('import npapp.management')
968+        settings_file.close()
969+
970+    def tearDown(self):
971+        self.remove_settings('settings.py')
972+
973+    def test_help(self):
974+        out, err = self.run_manage(['help'])
975+        self.assertNoOutput(err)
976+
977diff --git a/tests/regressiontests/templates/eggs/templatesegg.egg b/tests/regressiontests/templates/eggs/templatesegg.egg
978new file mode 100644
979index 0000000000000000000000000000000000000000..9a8f315f883b1d895f1d5926ca7ad3134c23287f
980GIT binary patch
981literal 663
982zcmWIWW@Zs#W&naW+0_mp8V1;ajMVh>ctiaFpc*c)npbFQ1mSAp<1_OzOXB183MxU$
983zAx3^eQ!W5kUXq$ykds)FT8v~kNVTZi?ca<*RUj;eMRlcKMoDfCk`>R<tl)xb0-9e^
984ziDWpsI#CpLD6VH@vS-E}BtU&YAkgsF5k$iR2&4yh5P?)OFeo%^X;cBy5Is1o#1>>=
985z-C!$&;o6Y{5MepCAcW`!S>A|6HzYs<yb+#84=GTHLIB9q+ki}v2Vmigup3<;D1;#Z
986cWcNKF6QK{q^Q@qh#=r)I1;A(*1Vudq052GO+5i9m
987
988literal 0
989HcmV?d00001
990
991diff --git a/tests/regressiontests/templates/loaders.py b/tests/regressiontests/templates/loaders.py
992index 5c11916..287bfdd 100644
993--- a/tests/regressiontests/templates/loaders.py
994+++ b/tests/regressiontests/templates/loaders.py
995@@ -1,7 +1,5 @@
996 """
997 Test cases for the template loaders
998-
999-Note: This test requires setuptools!
1000 """
1001 
1002 from django.conf import settings
1003@@ -10,65 +8,27 @@ if __name__ == '__main__':
1004     settings.configure()
1005 
1006 import sys
1007-import pkg_resources
1008 import imp
1009 import StringIO
1010 import os.path
1011 
1012 from django.template import TemplateDoesNotExist, Context
1013-from django.template.loaders.eggs import Loader as EggLoader
1014+from django.template.loaders.app_directories import Loader as EggLoader
1015 from django.template import loader
1016 from django.utils import unittest
1017 
1018 
1019-# Mock classes and objects for pkg_resources functions.
1020-class MockProvider(pkg_resources.NullProvider):
1021-    def __init__(self, module):
1022-        pkg_resources.NullProvider.__init__(self, module)
1023-        self.module = module
1024-
1025-    def _has(self, path):
1026-        return path in self.module._resources
1027-
1028-    def _isdir(self,path):
1029-        return False
1030-
1031-    def get_resource_stream(self, manager, resource_name):
1032-        return self.module._resources[resource_name]
1033-
1034-    def _get(self, path):
1035-        return self.module._resources[path].read()
1036-
1037-class MockLoader(object):
1038-    pass
1039-
1040-def create_egg(name, resources):
1041-    """
1042-    Creates a mock egg with a list of resources.
1043-
1044-    name: The name of the module.
1045-    resources: A dictionary of resources. Keys are the names and values the data.
1046-    """
1047-    egg = imp.new_module(name)
1048-    egg.__loader__ = MockLoader()
1049-    egg._resources = resources
1050-    sys.modules[name] = egg
1051-
1052-
1053 class EggLoaderTest(unittest.TestCase):
1054     def setUp(self):
1055-        pkg_resources._provider_factories[MockLoader] = MockProvider
1056-
1057-        self.empty_egg = create_egg("egg_empty", {})
1058-        self.egg_1 = create_egg("egg_1", {
1059-            os.path.normcase('templates/y.html') : StringIO.StringIO("y"),
1060-            os.path.normcase('templates/x.txt') : StringIO.StringIO("x"),
1061-        })
1062-        self._old_installed_apps = settings.INSTALLED_APPS
1063-        settings.INSTALLED_APPS = []
1064+        self.old_path = sys.path[:]
1065+        self.old_apps = settings.INSTALLED_APPS
1066+        self.egg_dir = '%s/eggs' % os.path.dirname(__file__)
1067+        egg_name = '%s/templatesegg.egg' % self.egg_dir
1068+        sys.path.append(egg_name)
1069 
1070     def tearDown(self):
1071-        settings.INSTALLED_APPS = self._old_installed_apps
1072+        settings.INSTALLED_APPS = self.old_apps
1073+        sys.path = self.old_path
1074 
1075     def test_empty(self):
1076         "Loading any template on an empty egg should fail"
1077@@ -88,7 +48,7 @@ class EggLoaderTest(unittest.TestCase):
1078         egg_loader = EggLoader()
1079         contents, template_name = egg_loader.load_template_source("y.html")
1080         self.assertEqual(contents, "y")
1081-        self.assertEqual(template_name, "egg:egg_1:templates/y.html")
1082+        self.assertEqual(template_name, u"app:egg_1:templates/y.html")
1083 
1084     def test_not_installed(self):
1085         "Loading an existent template from an egg not included in INSTALLED_APPS should fail"
1086diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
1087index f74aa75..a13c157 100644
1088--- a/tests/regressiontests/templates/tests.py
1089+++ b/tests/regressiontests/templates/tests.py
1090@@ -39,14 +39,8 @@ from .nodelist import NodelistTest, ErrorIndexTest
1091 from .smartif import SmartIfTests
1092 from .response import (TemplateResponseTest, BaseTemplateResponseTest,
1093     CacheMiddlewareTest, SimpleTemplateResponseTest, CustomURLConfTest)
1094+from .loaders import RenderToStringTest, EggLoaderTest
1095 
1096-try:
1097-    from .loaders import RenderToStringTest, EggLoaderTest
1098-except ImportError, e:
1099-    if "pkg_resources" in e.message:
1100-        pass # If setuptools isn't installed, that's fine. Just move on.
1101-    else:
1102-        raise
1103 
1104 from . import filters
1105 
1106@@ -167,20 +161,16 @@ class Templates(unittest.TestCase):
1107         restore_warnings_state(self._warnings_state)
1108 
1109     def test_loaders_security(self):
1110-        ad_loader = app_directories.Loader()
1111-        fs_loader = filesystem.Loader()
1112         def test_template_sources(path, template_dirs, expected_sources):
1113             if isinstance(expected_sources, list):
1114                 # Fix expected sources so they are abspathed
1115                 expected_sources = [os.path.abspath(s) for s in expected_sources]
1116-            # Test the two loaders (app_directores and filesystem).
1117-            func1 = lambda p, t: list(ad_loader.get_template_sources(p, t))
1118-            func2 = lambda p, t: list(fs_loader.get_template_sources(p, t))
1119-            for func in (func1, func2):
1120-                if isinstance(expected_sources, list):
1121-                    self.assertEqual(func(path, template_dirs), expected_sources)
1122-                else:
1123-                    self.assertRaises(expected_sources, func, path, template_dirs)
1124+            # Test filesystem loader.
1125+            func = lambda p, t: list(filesystem.Loader(t).get_template_sources(p))
1126+            if isinstance(expected_sources, list):
1127+                self.assertEqual(func(path, template_dirs), expected_sources)
1128+            else:
1129+                self.assertRaises(expected_sources, func, path, template_dirs)
1130 
1131         template_dirs = ['/dir1', '/dir2']
1132         test_template_sources('index.html', template_dirs,