From 6be20bf64c63180103ae92bfa6e068b8c8102b7a Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 6 Nov 2008 11:27:33 +0000 Subject: [PATCH] [1.0.X] Fixed #9011 -- Corrected handling of fixture files that contain errors to correctly report the broken fixture name. Thanks to jlrivitti@gmail.com for the report and initial patch. Merge of [9357] and [9358] from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@9359 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/management/commands/loaddata.py | 40 +++++++++---------- .../fixtures_regress/fixtures/empty.json | 1 + .../fixtures_regress/models.py | 15 +++++-- 3 files changed, 32 insertions(+), 24 deletions(-) create mode 100644 tests/regressiontests/fixtures_regress/fixtures/empty.json diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py index c69eeb96bd..a6a7871c52 100644 --- a/django/core/management/commands/loaddata.py +++ b/django/core/management/commands/loaddata.py @@ -28,19 +28,18 @@ class Command(BaseCommand): verbosity = int(options.get('verbosity', 1)) show_traceback = options.get('traceback', False) - - # commit is a stealth option - it isn't really useful as + + # commit is a stealth option - it isn't really useful as # a command line option, but it can be useful when invoking - # loaddata from within another script. + # loaddata from within another script. # If commit=True, loaddata will use its own transaction; # if commit=False, the data load SQL will become part of # the transaction in place when loaddata was invoked. commit = options.get('commit', True) - + # Keep a count of the installed objects and fixtures fixture_count = 0 object_count = 0 - objects_per_fixture = [] models = set() humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path' @@ -108,17 +107,17 @@ class Command(BaseCommand): return else: fixture_count += 1 - objects_per_fixture.append(0) + objects_in_fixture = 0 if verbosity > 0: print "Installing %s fixture '%s' from %s." % \ (format, fixture_name, humanize(fixture_dir)) try: objects = serializers.deserialize(format, fixture) for obj in objects: - object_count += 1 - objects_per_fixture[-1] += 1 + objects_in_fixture += 1 models.add(obj.object.__class__) obj.save() + object_count += objects_in_fixture label_found = True except (SystemExit, KeyboardInterrupt): raise @@ -136,22 +135,21 @@ class Command(BaseCommand): (full_path, traceback.format_exc()))) return fixture.close() + + # If the fixture we loaded contains 0 objects, assume that an + # error was encountered during fixture loading. + if objects_in_fixture == 0: + sys.stderr.write( + self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" % + (fixture_name))) + transaction.rollback() + transaction.leave_transaction_management() + return except: if verbosity > 1: print "No %s fixture '%s' in %s." % \ (format, fixture_name, humanize(fixture_dir)) - - # If any of the fixtures we loaded contain 0 objects, assume that an - # error was encountered during fixture loading. - if 0 in objects_per_fixture: - sys.stderr.write( - self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" % - (fixture_name))) - transaction.rollback() - transaction.leave_transaction_management() - return - # If we found even one object in a fixture, we need to reset the # database sequences. if object_count > 0: @@ -161,7 +159,7 @@ class Command(BaseCommand): print "Resetting sequences" for line in sequence_sql: cursor.execute(line) - + if commit: transaction.commit() transaction.leave_transaction_management() @@ -172,7 +170,7 @@ class Command(BaseCommand): else: if verbosity > 0: print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count) - + # Close the DB connection. This is required as a workaround for an # edge case in MySQL: if the same connection is used to # create tables, load data, and query, the query can return diff --git a/tests/regressiontests/fixtures_regress/fixtures/empty.json b/tests/regressiontests/fixtures_regress/fixtures/empty.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/tests/regressiontests/fixtures_regress/fixtures/empty.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py index 9bca78bc59..373980bb66 100644 --- a/tests/regressiontests/fixtures_regress/models.py +++ b/tests/regressiontests/fixtures_regress/models.py @@ -7,7 +7,7 @@ class Animal(models.Model): name = models.CharField(max_length=150) latin_name = models.CharField(max_length=150) count = models.IntegerField() - + def __unicode__(self): return self.common_name @@ -56,7 +56,7 @@ class Channel(models.Model): class Article(models.Model): title = models.CharField(max_length=255) channels = models.ManyToManyField(Channel) - + class Meta: ordering = ('id',) @@ -113,6 +113,15 @@ No fixture data found for 'bad_fixture2'. (File format may be invalid.) >>> management.call_command('loaddata', 'bad_fixture2', verbosity=0) No fixture data found for 'bad_fixture2'. (File format may be invalid.) +# Loading a fixture file with no data returns an error +>>> management.call_command('loaddata', 'empty', verbosity=0) +No fixture data found for 'empty'. (File format may be invalid.) + +# If any of the fixtures contain an error, loading is aborted +# (Regression for #9011 - error message is correct) +>>> management.call_command('loaddata', 'bad_fixture2', 'animal', verbosity=0) +No fixture data found for 'bad_fixture2'. (File format may be invalid.) + >>> sys.stderr = savestderr ############################################### @@ -123,7 +132,7 @@ No fixture data found for 'bad_fixture2'. (File format may be invalid.) >>> management.call_command('loaddata', 'model-inheritance.json', verbosity=0) ############################################### -# Test for ticket #7572 -- MySQL has a problem if the same connection is +# Test for ticket #7572 -- MySQL has a problem if the same connection is # used to create tables, load data, and then query over that data. # To compensate, we close the connection after running loaddata. # This ensures that a new connection is opened when test queries are issued.