Commit 4c18a8a3 authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #14098 -- Prevented crash for introspection errors in inspectdb

Thanks Tim Graham for the review.
parent 441c537b
Loading
Loading
Loading
Loading
+21 −13
Original line number Diff line number Diff line
@@ -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,10 +58,7 @@ class Command(BaseCommand):
                if table_name_filter is not None and callable(table_name_filter):
                    if not table_name_filter(table_name):
                        continue
                yield ''
                yield ''
                yield 'class %s(models.Model):' % table2model(table_name)
                known_models.append(table2model(table_name))
                try:
                    try:
                        relations = connection.introspection.get_relations(cursor, table_name)
                    except NotImplementedError:
@@ -73,9 +71,19 @@ class Command(BaseCommand):
                        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))
                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]
+16 −1
Original line number Diff line number Diff line
@@ -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)