summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2015-01-02 17:58:58 +0100
committerClaude Paroz <claude@2xlibre.net>2015-01-05 17:19:35 +0100
commit6e1c9c6568c405bfa481dda4249abe2960173547 (patch)
tree12810d919e3f0e35cd8e277ec996fb9e851a786e
parentd94fe42ae5e67e9fd600d204a08eef00cc10a7df (diff)
Fixed #8280 -- Allowed management command discovery for eggs
Thanks jdetaeye for the report, bhuztez and jdetaeye for the initial patches, Tim Graham and Berker Peksag for the reviews.
-rw-r--r--django/core/management/__init__.py10
-rw-r--r--docs/releases/1.8.txt2
-rw-r--r--tests/user_commands/eggs/basic.eggbin0 -> 3465 bytes
-rw-r--r--tests/user_commands/tests.py17
4 files changed, 22 insertions, 7 deletions
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index b88026a335..a0c86024b9 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
import collections
from importlib import import_module
import os
+import pkgutil
import sys
import django
@@ -24,11 +25,10 @@ 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:
- return []
+ # Workaround for a Python 3.2 bug with pkgutil.iter_modules
+ sys.path_importer_cache.pop(command_dir, None)
+ return [name for _, name, is_pkg in pkgutil.iter_modules([command_dir])
+ if not is_pkg and not name.startswith('_')]
def load_command_class(app_name, name):
diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt
index b69e69db49..d6e139606d 100644
--- a/docs/releases/1.8.txt
+++ b/docs/releases/1.8.txt
@@ -371,6 +371,8 @@ Management Commands
* Database connections are now always closed after a management command called
from the command line has finished doing its job.
+* Commands from alternate package formats like eggs are now also discovered.
+
* :djadmin:`dumpdata` now has the option :djadminopt:`--output` which allows
specifying the file to which the serialized data is written.
diff --git a/tests/user_commands/eggs/basic.egg b/tests/user_commands/eggs/basic.egg
new file mode 100644
index 0000000000..cb25c6d8cf
--- /dev/null
+++ b/tests/user_commands/eggs/basic.egg
Binary files differ
diff --git a/tests/user_commands/tests.py b/tests/user_commands/tests.py
index 6a5677f2c9..dff7dcaed5 100644
--- a/tests/user_commands/tests.py
+++ b/tests/user_commands/tests.py
@@ -1,13 +1,15 @@
import os
+from django.apps import apps
from django.db import connection
from django.core import management
-from django.core.management import BaseCommand, CommandError
+from django.core.management import BaseCommand, CommandError, find_commands
from django.core.management.utils import find_command, popen_wrapper
from django.test import SimpleTestCase, ignore_warnings
-from django.test.utils import captured_stderr, captured_stdout
+from django.test.utils import captured_stderr, captured_stdout, extend_sys_path
from django.utils import translation
from django.utils.deprecation import RemovedInDjango20Warning
+from django.utils._os import upath
from django.utils.six import StringIO
@@ -72,6 +74,17 @@ class CommandTests(SimpleTestCase):
if current_path is not None:
os.environ['PATH'] = current_path
+ def test_discover_commands_in_eggs(self):
+ """
+ Test that management commands can also be loaded from Python eggs.
+ """
+ egg_dir = '%s/eggs' % os.path.dirname(upath(__file__))
+ egg_name = '%s/basic.egg' % egg_dir
+ with extend_sys_path(egg_name):
+ with self.settings(INSTALLED_APPS=['commandegg']):
+ cmds = find_commands(os.path.join(apps.get_app_config('commandegg').path, 'management'))
+ self.assertEqual(cmds, ['eggcommand'])
+
def test_call_command_option_parsing(self):
"""
When passing the long option name to call_command, the available option