summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2016-02-24 20:16:49 +0100
committerClaude Paroz <claude@2xlibre.net>2016-02-25 08:43:56 +0100
commit4c18a8a3788a4cd25b75ae342a7244c5f775b213 (patch)
tree29621ddf6d7e60df13eb8fb8fbb841f659c602a0
parent441c537b66233ae57bf0023f02d8262474229e1a (diff)
Fixed #14098 -- Prevented crash for introspection errors in inspectdb
Thanks Tim Graham for the review.
-rw-r--r--django/core/management/commands/inspectdb.py34
-rw-r--r--tests/inspectdb/tests.py17
2 files changed, 37 insertions, 14 deletions
diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py
index 3bb8e75924..982ba7f1bd 100644
--- a/django/core/management/commands/inspectdb.py
+++ b/django/core/management/commands/inspectdb.py
@@ -6,6 +6,7 @@ from collections import OrderedDict
from django.core.management.base import BaseCommand, CommandError
from django.db import DEFAULT_DB_ALIAS, connections
+from django.utils.encoding import force_text
class Command(BaseCommand):
@@ -57,25 +58,32 @@ class Command(BaseCommand):
if table_name_filter is not None and callable(table_name_filter):
if not table_name_filter(table_name):
continue
+ try:
+ try:
+ relations = connection.introspection.get_relations(cursor, table_name)
+ except NotImplementedError:
+ relations = {}
+ try:
+ indexes = connection.introspection.get_indexes(cursor, table_name)
+ except NotImplementedError:
+ indexes = {}
+ try:
+ constraints = connection.introspection.get_constraints(cursor, table_name)
+ except NotImplementedError:
+ constraints = {}
+ table_description = connection.introspection.get_table_description(cursor, table_name)
+ except Exception as e:
+ yield "# Unable to inspect table '%s'" % table_name
+ yield "# The error was: %s" % force_text(e)
+ continue
+
yield ''
yield ''
yield 'class %s(models.Model):' % table2model(table_name)
known_models.append(table2model(table_name))
- try:
- relations = connection.introspection.get_relations(cursor, table_name)
- except NotImplementedError:
- relations = {}
- try:
- indexes = connection.introspection.get_indexes(cursor, table_name)
- except NotImplementedError:
- indexes = {}
- try:
- constraints = connection.introspection.get_constraints(cursor, table_name)
- except NotImplementedError:
- constraints = {}
used_column_names = [] # Holds column names used in the table so far
column_to_field_name = {} # Maps column names to names of model fields
- for row in connection.introspection.get_table_description(cursor, table_name):
+ for row in table_description:
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
extra_params = OrderedDict() # Holds Field parameters such as 'db_column'.
column_name = row[0]
diff --git a/tests/inspectdb/tests.py b/tests/inspectdb/tests.py
index 06eb2c82f8..6fd1778b55 100644
--- a/tests/inspectdb/tests.py
+++ b/tests/inspectdb/tests.py
@@ -6,7 +6,8 @@ from unittest import skipUnless
from django.core.management import call_command
from django.db import connection
-from django.test import TestCase, skipUnlessDBFeature
+from django.test import TestCase, mock, skipUnlessDBFeature
+from django.utils.encoding import force_text
from django.utils.six import PY3, StringIO
from .models import ColumnTypes
@@ -268,3 +269,17 @@ class InspectDBTestCase(TestCase):
self.assertIn("big_int_field = models.BigIntegerField()", output)
finally:
connection.introspection.data_types_reverse = orig_data_types_reverse
+
+ def test_introspection_errors(self):
+ """
+ Introspection errors should not crash the command, and the error should
+ be visible in the output.
+ """
+ out = StringIO()
+ with mock.patch('django.db.backends.base.introspection.BaseDatabaseIntrospection.table_names',
+ return_value=['nonexistent']):
+ call_command('inspectdb', stdout=out)
+ output = force_text(out.getvalue())
+ self.assertIn("# Unable to inspect table 'nonexistent'", output)
+ # The error message depends on the backend
+ self.assertIn("# The error was:", output)