From 6fd1950a4e29c1b5ed071a880db64103715ead51 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Thu, 7 Jun 2012 10:31:08 +0200 Subject: [PATCH] Fixed #10200 -- Raised CommandError when errors happen in loaddata. --- django/core/management/commands/loaddata.py | 43 ++---- tests/modeltests/fixtures/tests.py | 25 ++- .../regressiontests/fixtures_regress/tests.py | 142 ++++++++---------- 3 files changed, 81 insertions(+), 129 deletions(-) diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py index f44edf7ade..078fd6fa27 100644 --- a/django/core/management/commands/loaddata.py +++ b/django/core/management/commands/loaddata.py @@ -7,7 +7,7 @@ import traceback from django.conf import settings from django.core import serializers -from django.core.management.base import BaseCommand +from django.core.management.base import BaseCommand, CommandError from django.core.management.color import no_style from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS, IntegrityError, DatabaseError) @@ -36,11 +36,10 @@ class Command(BaseCommand): connection = connections[using] if not len(fixture_labels): - self.stderr.write( + raise CommandError( "No database fixture specified. Please provide the path of at " "least one fixture in the command line." ) - return verbosity = int(options.get('verbosity')) show_traceback = options.get('traceback') @@ -126,13 +125,9 @@ class Command(BaseCommand): if verbosity >= 2: self.stdout.write("Loading '%s' fixtures..." % fixture_name) else: - self.stderr.write( + raise CommandError( "Problem installing fixture '%s': %s is not a known serialization format." % (fixture_name, format)) - if commit: - transaction.rollback(using=using) - transaction.leave_transaction_management(using=using) - return if os.path.isabs(fixture_name): fixture_dirs = [fixture_name] @@ -167,12 +162,8 @@ class Command(BaseCommand): else: try: if label_found: - self.stderr.write("Multiple fixtures named '%s' in %s. Aborting." % + raise CommandError("Multiple fixtures named '%s' in %s. Aborting." % (fixture_name, humanize(fixture_dir))) - if commit: - transaction.rollback(using=using) - transaction.leave_transaction_management(using=using) - return fixture_count += 1 objects_in_fixture = 0 @@ -191,13 +182,13 @@ class Command(BaseCommand): try: obj.save(using=using) except (DatabaseError, IntegrityError) as e: - msg = "Could not load %(app_label)s.%(object_name)s(pk=%(pk)s): %(error_msg)s" % { + e.args = ("Could not load %(app_label)s.%(object_name)s(pk=%(pk)s): %(error_msg)s" % { 'app_label': obj.object._meta.app_label, 'object_name': obj.object._meta.object_name, 'pk': obj.object.pk, 'error_msg': e - } - raise e.__class__, e.__class__(msg), sys.exc_info()[2] + },) + raise loaded_object_count += loaded_objects_in_fixture fixture_object_count += objects_in_fixture @@ -208,13 +199,9 @@ class Command(BaseCommand): # If the fixture we loaded contains 0 objects, assume that an # error was encountered during fixture loading. if objects_in_fixture == 0: - self.stderr.write( + raise CommandError( "No fixture data found for '%s'. (File format may be invalid.)" % (fixture_name)) - if commit: - transaction.rollback(using=using) - transaction.leave_transaction_management(using=using) - return # Since we disabled constraint checks, we must manually check for # any invalid keys that might have been added @@ -223,19 +210,13 @@ class Command(BaseCommand): except (SystemExit, KeyboardInterrupt): raise - except Exception: + except Exception as e: if commit: transaction.rollback(using=using) transaction.leave_transaction_management(using=using) - if show_traceback: - traceback.print_exc() - else: - self.stderr.write( - "Problem installing fixture '%s': %s" % - (full_path, ''.join(traceback.format_exception(sys.exc_type, - sys.exc_value, sys.exc_traceback)))) - return - + if not isinstance(e, CommandError): + e.args = ("Problem installing fixture '%s': %s" % (full_path, e),) + raise # If we found even one object in a fixture, we need to reset the # database sequences. diff --git a/tests/modeltests/fixtures/tests.py b/tests/modeltests/fixtures/tests.py index 478bbe9129..f5176dab0c 100644 --- a/tests/modeltests/fixtures/tests.py +++ b/tests/modeltests/fixtures/tests.py @@ -4,7 +4,7 @@ import StringIO from django.contrib.sites.models import Site from django.core import management -from django.db import connection +from django.db import connection, IntegrityError from django.test import TestCase, TransactionTestCase, skipUnlessDBFeature from .models import Article, Book, Spy, Tag, Visa @@ -232,11 +232,9 @@ class FixtureLoadingTests(TestCase): def test_ambiguous_compressed_fixture(self): # The name "fixture5" is ambigous, so loading it will raise an error - new_io = StringIO.StringIO() - management.call_command('loaddata', 'fixture5', verbosity=0, stderr=new_io, commit=False) - output = new_io.getvalue().strip().split('\n') - self.assertEqual(len(output), 1) - self.assertTrue(output[0].startswith("Multiple fixtures named 'fixture5'")) + with self.assertRaisesRegexp(management.CommandError, + "Multiple fixtures named 'fixture5'"): + management.call_command('loaddata', 'fixture5', verbosity=0, commit=False) def test_db_loading(self): # Load db fixtures 1 and 2. These will load using the 'default' database identifier implicitly @@ -258,10 +256,9 @@ class FixtureLoadingTests(TestCase): # is closed at the end of each test. if connection.vendor == 'mysql': connection.cursor().execute("SET sql_mode = 'TRADITIONAL'") - new_io = StringIO.StringIO() - management.call_command('loaddata', 'invalid.json', verbosity=0, stderr=new_io, commit=False) - output = new_io.getvalue().strip().split('\n') - self.assertRegexpMatches(output[-1], "Error: Could not load fixtures.Article\(pk=1\): .*$") + with self.assertRaisesRegexp(IntegrityError, + "Could not load fixtures.Article\(pk=1\): .*$"): + management.call_command('loaddata', 'invalid.json', verbosity=0, commit=False) def test_loading_using(self): # Load db fixtures 1 and 2. These will load using the 'default' database identifier explicitly @@ -316,11 +313,9 @@ class FixtureTransactionTests(TransactionTestCase): # Try to load fixture 2 using format discovery; this will fail # because there are two fixture2's in the fixtures directory - new_io = StringIO.StringIO() - management.call_command('loaddata', 'fixture2', verbosity=0, stderr=new_io) - output = new_io.getvalue().strip().split('\n') - self.assertEqual(len(output), 1) - self.assertTrue(output[0].startswith("Multiple fixtures named 'fixture2'")) + with self.assertRaisesRegexp(management.CommandError, + "Multiple fixtures named 'fixture2'"): + management.call_command('loaddata', 'fixture2', verbosity=0) # object list is unaffected self.assertQuerysetEqual(Article.objects.all(), [ diff --git a/tests/regressiontests/fixtures_regress/tests.py b/tests/regressiontests/fixtures_regress/tests.py index 0e2cc3a9b2..c0b811bea2 100644 --- a/tests/regressiontests/fixtures_regress/tests.py +++ b/tests/regressiontests/fixtures_regress/tests.py @@ -9,7 +9,7 @@ from io import BytesIO from django.core import management from django.core.management.base import CommandError from django.core.management.commands.dumpdata import sort_dependencies -from django.db import transaction +from django.db import transaction, IntegrityError from django.db.models import signals from django.test import (TestCase, TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature) @@ -116,18 +116,15 @@ class TestFixtures(TestCase): Test for ticket #4371 -- Loading data of an unknown format should fail Validate that error conditions are caught correctly """ - stderr = BytesIO() - management.call_command( - 'loaddata', - 'bad_fixture1.unkn', - verbosity=0, - commit=False, - stderr=stderr, - ) - self.assertEqual( - stderr.getvalue(), - "Problem installing fixture 'bad_fixture1': unkn is not a known serialization format.\n" - ) + with self.assertRaisesRegexp(management.CommandError, + "Problem installing fixture 'bad_fixture1': " + "unkn is not a known serialization format."): + management.call_command( + 'loaddata', + 'bad_fixture1.unkn', + verbosity=0, + commit=False, + ) def test_invalid_data(self): """ @@ -135,18 +132,14 @@ class TestFixtures(TestCase): using explicit filename. Validate that error conditions are caught correctly """ - stderr = BytesIO() - management.call_command( - 'loaddata', - 'bad_fixture2.xml', - verbosity=0, - commit=False, - stderr=stderr, - ) - self.assertEqual( - stderr.getvalue(), - "No fixture data found for 'bad_fixture2'. (File format may be invalid.)\n" - ) + with self.assertRaisesRegexp(management.CommandError, + "No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)"): + management.call_command( + 'loaddata', + 'bad_fixture2.xml', + verbosity=0, + commit=False, + ) def test_invalid_data_no_ext(self): """ @@ -154,54 +147,42 @@ class TestFixtures(TestCase): without file extension. Validate that error conditions are caught correctly """ - stderr = BytesIO() - management.call_command( - 'loaddata', - 'bad_fixture2', - verbosity=0, - commit=False, - stderr=stderr, - ) - self.assertEqual( - stderr.getvalue(), - "No fixture data found for 'bad_fixture2'. (File format may be invalid.)\n" - ) + with self.assertRaisesRegexp(management.CommandError, + "No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)"): + management.call_command( + 'loaddata', + 'bad_fixture2', + verbosity=0, + commit=False, + ) def test_empty(self): """ Test for ticket #4371 -- Loading a fixture file with no data returns an error. Validate that error conditions are caught correctly """ - stderr = BytesIO() - management.call_command( - 'loaddata', - 'empty', - verbosity=0, - commit=False, - stderr=stderr, - ) - self.assertEqual( - stderr.getvalue(), - "No fixture data found for 'empty'. (File format may be invalid.)\n" - ) + with self.assertRaisesRegexp(management.CommandError, + "No fixture data found for 'empty'. \(File format may be invalid.\)"): + management.call_command( + 'loaddata', + 'empty', + verbosity=0, + commit=False, + ) def test_error_message(self): """ (Regression for #9011 - error message is correct) """ - stderr = BytesIO() - management.call_command( - 'loaddata', - 'bad_fixture2', - 'animal', - verbosity=0, - commit=False, - stderr=stderr, - ) - self.assertEqual( - stderr.getvalue(), - "No fixture data found for 'bad_fixture2'. (File format may be invalid.)\n" - ) + with self.assertRaisesRegexp(management.CommandError, + "^No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)$"): + management.call_command( + 'loaddata', + 'bad_fixture2', + 'animal', + verbosity=0, + commit=False, + ) def test_pg_sequence_resetting_checks(self): """ @@ -357,17 +338,14 @@ class TestFixtures(TestCase): """ Regression for #3615 - Ensure data with nonexistent child key references raises error """ - stderr = BytesIO() - management.call_command( - 'loaddata', - 'forward_ref_bad_data.json', - verbosity=0, - commit=False, - stderr=stderr, - ) - self.assertTrue( - stderr.getvalue().startswith('Problem installing fixture') - ) + with self.assertRaisesRegexp(IntegrityError, + "Problem installing fixture"): + management.call_command( + 'loaddata', + 'forward_ref_bad_data.json', + verbosity=0, + commit=False, + ) _cur_dir = os.path.dirname(os.path.abspath(__file__)) @@ -392,16 +370,14 @@ class TestFixtures(TestCase): """ Regression for #7043 - Error is quickly reported when no fixtures is provided in the command line. """ - stderr = BytesIO() - management.call_command( - 'loaddata', - verbosity=0, - commit=False, - stderr=stderr, - ) - self.assertEqual( - stderr.getvalue(), 'No database fixture specified. Please provide the path of at least one fixture in the command line.\n' - ) + with self.assertRaisesRegexp(management.CommandError, + "No database fixture specified. Please provide the path of " + "at least one fixture in the command line."): + management.call_command( + 'loaddata', + verbosity=0, + commit=False, + ) def test_loaddata_not_existant_fixture_file(self): stdout_output = BytesIO()