Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fixes issue 18685 and addresses part of 18603 #241

Closed
wants to merge 2 commits into from

2 participants

@cberner

Change the way that management commands are found to use pkgutil instead of the imp library. This resolves issues related to PEP 302, where modules in the same package distributed in separate pip packages didn't work properly

cberner added some commits
@cberner cberner Change the way that management modules are found to use pkgutil instead
of imp, so that multiple modules in the same heirarchy can be installed
from different setuptools packages. Addresses ticket #18685
be5eb95
@cberner cberner Add regression test for ticket #18685, which tests that loading
management commands from two different setuptools packages, that are in
the same parent module works correctly.
6c17f76
@cberner cberner closed this
@cberner

Worked great, thanks! I found your branch, that's why I closed my pull request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 30, 2012
  1. @cberner

    Change the way that management modules are found to use pkgutil instead

    cberner authored
    of imp, so that multiple modules in the same heirarchy can be installed
    from different setuptools packages. Addresses ticket #18685
Commits on Jul 31, 2012
  1. @cberner

    Add regression test for ticket #18685, which tests that loading

    cberner authored
    management commands from two different setuptools packages, that are in
    the same parent module works correctly.
This page is out of date. Refresh to see the latest.
Showing with 53 additions and 16 deletions.
  1. +10 −16 django/core/management/__init__.py
  2. 0  tests/regressiontests/admin_scripts/find_command_submodules/project-A/mypackage/A/__init__.py
  3. 0  tests/regressiontests/admin_scripts/find_command_submodules/project-A/mypackage/A/management/__init__.py
  4. 0  ...regressiontests/admin_scripts/find_command_submodules/project-A/mypackage/A/management/commands/__init__.py
  5. +5 −0 ...egressiontests/admin_scripts/find_command_submodules/project-A/mypackage/A/management/commands/command_A.py
  6. +2 −0  tests/regressiontests/admin_scripts/find_command_submodules/project-A/mypackage/__init__.py
  7. 0  tests/regressiontests/admin_scripts/find_command_submodules/project-B/mypackage/B/__init__.py
  8. 0  tests/regressiontests/admin_scripts/find_command_submodules/project-B/mypackage/B/management/__init__.py
  9. 0  ...regressiontests/admin_scripts/find_command_submodules/project-B/mypackage/B/management/commands/__init__.py
  10. +5 −0 ...egressiontests/admin_scripts/find_command_submodules/project-B/mypackage/B/management/commands/command_B.py
  11. +2 −0  tests/regressiontests/admin_scripts/find_command_submodules/project-B/mypackage/__init__.py
  12. +4 −0 tests/regressiontests/admin_scripts/find_command_submodules/site-packages/easy-install.pth
  13. +2 −0  tests/regressiontests/admin_scripts/find_command_submodules/site-packages/mypackage-A.egg-link
  14. +2 −0  tests/regressiontests/admin_scripts/find_command_submodules/site-packages/mypackage-B.egg-link
  15. +21 −0 tests/regressiontests/admin_scripts/tests.py
View
26 django/core/management/__init__.py
@@ -2,7 +2,7 @@
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
@@ -37,11 +37,8 @@ def find_management_module(app_name):
Raises ImportError if the management module cannot be found for any reason.
"""
- parts = app_name.split('.')
- parts.append('management')
- parts.reverse()
- part = parts.pop()
- path = None
+ module_name = app_name + ".management"
+ loader = pkgutil.find_loader(module_name)
# When using manage.py, the project module is added to the path,
# loaded, then removed from the path. This means that
@@ -49,16 +46,13 @@ def find_management_module(app_name):
# 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 as 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
+ if not loader and os.path.basename(os.getcwd()) == module_name.split('.')[0]:
+ loader = pkgutil.find_loader(".".join(module_name.split(".")[1:]))
+
+ if loader:
+ return loader.filename
+ else:
+ return ''
def load_command_class(app_name, name):
"""
View
0  tests/regressiontests/admin_scripts/find_command_submodules/project-A/mypackage/A/__init__.py
No changes.
View
0  tests/regressiontests/admin_scripts/find_command_submodules/project-A/mypackage/A/management/__init__.py
No changes.
View
0  ...ressiontests/admin_scripts/find_command_submodules/project-A/mypackage/A/management/commands/__init__.py
No changes.
View
5 ...essiontests/admin_scripts/find_command_submodules/project-A/mypackage/A/management/commands/command_A.py
@@ -0,0 +1,5 @@
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+ def handle(self, *args, **options):
+ print "Command A"
View
2  tests/regressiontests/admin_scripts/find_command_submodules/project-A/mypackage/__init__.py
@@ -0,0 +1,2 @@
+from pkgutil import extend_path
+__path__ = extend_path(__path__, __name__)
View
0  tests/regressiontests/admin_scripts/find_command_submodules/project-B/mypackage/B/__init__.py
No changes.
View
0  tests/regressiontests/admin_scripts/find_command_submodules/project-B/mypackage/B/management/__init__.py
No changes.
View
0  ...ressiontests/admin_scripts/find_command_submodules/project-B/mypackage/B/management/commands/__init__.py
No changes.
View
5 ...essiontests/admin_scripts/find_command_submodules/project-B/mypackage/B/management/commands/command_B.py
@@ -0,0 +1,5 @@
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+ def handle(self, *args, **options):
+ print "Command B"
View
2  tests/regressiontests/admin_scripts/find_command_submodules/project-B/mypackage/__init__.py
@@ -0,0 +1,2 @@
+from pkgutil import extend_path
+__path__ = extend_path(__path__, __name__)
View
4 tests/regressiontests/admin_scripts/find_command_submodules/site-packages/easy-install.pth
@@ -0,0 +1,4 @@
+import sys; sys.__plen = len(sys.path)
+../project-B
+../project-A
+import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)
View
2  tests/regressiontests/admin_scripts/find_command_submodules/site-packages/mypackage-A.egg-link
@@ -0,0 +1,2 @@
+../project-A
+.
View
2  tests/regressiontests/admin_scripts/find_command_submodules/site-packages/mypackage-B.egg-link
@@ -0,0 +1,2 @@
+../project-B
+.
View
21 tests/regressiontests/admin_scripts/tests.py
@@ -10,6 +10,7 @@
import socket
import subprocess
import sys
+import site
from django import conf, bin, get_version
from django.conf import settings
@@ -17,6 +18,7 @@
from django.test.simple import DjangoTestSuiteRunner
from django.utils import unittest
from django.test import LiveServerTestCase
+from django.core.management import find_management_module
test_dir = os.path.dirname(os.path.dirname(__file__))
@@ -1094,6 +1096,25 @@ def test_liveserver(self):
else:
del os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS']
+class FindCommandTest(AdminScriptTestCase):
+ def setUp(self):
+ self.old_path = sys.path
+ #Add the package directories to the sys path, like setuptools would do,
+ #when running the 'develop' command via an egg-link
+ site.addsitedir(os.path.join(os.path.dirname(__file__), "find_command_submodules/site-packages"))
+
+ def test_modules_from_different_setuptools_packages(self):
+ """Test for ticket 18685. Check that multiple modules in the same package,
+ installed from different setuptools packages, load their management commands
+ correctly.
+ """
+ module_A_path = find_management_module("mypackage.A")
+ self.assertTrue(module_A_path.endswith("project-A/mypackage/A/management"), module_A_path)
+ module_B_path = find_management_module("mypackage.B")
+ self.assertTrue(module_B_path.endswith("project-B/mypackage/B/management"), module_B_path)
+
+ def tearDown(self):
+ sys.path = self.old_path
class ManageRunserver(AdminScriptTestCase):
def setUp(self):
Something went wrong with that request. Please try again.