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/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/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 literal 2210 zcmWIWW@Zs#W&na+g#z{<8U{Fl3|Dt|T~9wZfBgWcG7g3{KxHDAuKle5O78$-K~!ZB z^|5C+avd@dV0&QeKT+IcWwzNt$AHBOuWGiW^E|0~S|nLhZ9Ow6Z`b?h&-X7l#KHBh zGf2q)-n(7*SQNg9C6^pYKAZ6`^S*BSyQv&cUcXhIbLgw+nTectc?6~3uC9yNw%@sF z%ItZU8-gRR@
d`@Owb}`85T&Q|ip0Nz)2I>J}F=V|Z`33Pgsb#4-AWf<1>G8SwDWy57
zXxfpjMv2p^%mUrw#59O{NK!eBmQ+AiA`Av67Koo#6`-amkh_o+#>Z#oWtPOp>lIYO
zVvd0U-EcHLxrup+>8ZJ?c_m2p+{#0>M-kN?Bt1k~DUVZoa(*t*u#{pvc54yVjKvWg
z3_F2gHQm(j`*xsy9$*5{C2S5TD4{L_2BB}CcONJzf46gee`Y}-UxUeP$C<(gLc3RV
zY9Cwi_n@qWz2AwZxYCuY=4Gw2oV2^}(@yDPS8>aY?k=--b8BlHne^Ic|6BWKH)7Jy
zXsq#?eWx}ep56KFx(QD9DgGB`hCMj6_@itPSErDB#zVor9U@z^*FXBlA!>Exjl$u{
zsuuH{{dm6}Ulb7>vsbSqJM5*w#jS~~)~!DGw}|g^*kb!TX4*Er&D*q1x2SHj|9<>`
zaDBt~!)B*vi6f