Browse Source

Fixed #13636 -- Migrated fixtures tests to use unittests, eliminating another set of expensive flush calls. Thanks to Eric Holscher for the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13319 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Russell Keith-Magee 15 years ago
parent
commit
5da6aeba17

+ 7 - 5
django/core/management/base.py

@@ -213,6 +213,8 @@ class BaseCommand(object):
                 sys.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
                 sys.exit(1)
         try:
+            self.stdout = options.get('stdout', sys.stdout)
+            self.stderr = options.get('stderr', sys.stderr)
             if self.requires_model_validation:
                 self.validate()
             output = self.handle(*args, **options)
@@ -223,12 +225,12 @@ class BaseCommand(object):
                     from django.db import connections, DEFAULT_DB_ALIAS
                     connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
                     if connection.ops.start_transaction_sql():
-                        print self.style.SQL_KEYWORD(connection.ops.start_transaction_sql())
-                print output
+                        self.stdout.write(self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()))
+                self.stdout.write(output)
                 if self.output_transaction:
-                    print self.style.SQL_KEYWORD(connection.ops.end_transaction_sql())
+                    self.stdout.write(self.style.SQL_KEYWORD("COMMIT;") + '\n')
         except CommandError, e:
-            sys.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
+            self.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
             sys.exit(1)
 
     def validate(self, app=None, display_num_errors=False):
@@ -250,7 +252,7 @@ class BaseCommand(object):
             error_text = s.read()
             raise CommandError("One or more models did not validate:\n%s" % error_text)
         if display_num_errors:
-            print "%s error%s found" % (num_errors, num_errors != 1 and 's' or '')
+            self.stdout.write("%s error%s found\n" % (num_errors, num_errors != 1 and 's' or ''))
 
     def handle(self, *args, **options):
         """

+ 15 - 15
django/core/management/commands/loaddata.py

@@ -112,10 +112,10 @@ class Command(BaseCommand):
 
             if formats:
                 if verbosity > 1:
-                    print "Loading '%s' fixtures..." % fixture_name
+                    self.stdout.write("Loading '%s' fixtures...\n" % fixture_name)
             else:
                 sys.stderr.write(
-                    self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format." %
+                    self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format.\n" %
                         (fixture_name, format)))
                 transaction.rollback(using=using)
                 transaction.leave_transaction_management(using=using)
@@ -128,7 +128,7 @@ class Command(BaseCommand):
 
             for fixture_dir in fixture_dirs:
                 if verbosity > 1:
-                    print "Checking %s for fixtures..." % humanize(fixture_dir)
+                    self.stdout.write("Checking %s for fixtures...\n" % humanize(fixture_dir))
 
                 label_found = False
                 for combo in product([using, None], formats, compression_formats):
@@ -141,16 +141,16 @@ class Command(BaseCommand):
                     )
 
                     if verbosity > 1:
-                        print "Trying %s for %s fixture '%s'..." % \
-                            (humanize(fixture_dir), file_name, fixture_name)
+                        self.stdout.write("Trying %s for %s fixture '%s'...\n" % \
+                            (humanize(fixture_dir), file_name, fixture_name))
                     full_path = os.path.join(fixture_dir, file_name)
                     open_method = compression_types[compression_format]
                     try:
                         fixture = open_method(full_path, 'r')
                         if label_found:
                             fixture.close()
-                            print self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting." %
-                                (fixture_name, humanize(fixture_dir)))
+                            self.stderr.write(self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting.\n" %
+                                (fixture_name, humanize(fixture_dir))))
                             transaction.rollback(using=using)
                             transaction.leave_transaction_management(using=using)
                             return
@@ -158,8 +158,8 @@ class Command(BaseCommand):
                             fixture_count += 1
                             objects_in_fixture = 0
                             if verbosity > 0:
-                                print "Installing %s fixture '%s' from %s." % \
-                                    (format, fixture_name, humanize(fixture_dir))
+                                self.stdout.write("Installing %s fixture '%s' from %s.\n" % \
+                                    (format, fixture_name, humanize(fixture_dir)))
                             try:
                                 objects = serializers.deserialize(format, fixture, using=using)
                                 for obj in objects:
@@ -190,7 +190,7 @@ class Command(BaseCommand):
                             # 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.)" %
+                                    self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)\n" %
                                         (fixture_name)))
                                 transaction.rollback(using=using)
                                 transaction.leave_transaction_management(using=using)
@@ -198,8 +198,8 @@ class Command(BaseCommand):
 
                     except Exception, e:
                         if verbosity > 1:
-                            print "No %s fixture '%s' in %s." % \
-                                (format, fixture_name, humanize(fixture_dir))
+                            self.stdout.write("No %s fixture '%s' in %s.\n" % \
+                                (format, fixture_name, humanize(fixture_dir)))
 
         # If we found even one object in a fixture, we need to reset the
         # database sequences.
@@ -207,7 +207,7 @@ class Command(BaseCommand):
             sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
             if sequence_sql:
                 if verbosity > 1:
-                    print "Resetting sequences"
+                    self.stdout.write("Resetting sequences\n")
                 for line in sequence_sql:
                     cursor.execute(line)
 
@@ -217,10 +217,10 @@ class Command(BaseCommand):
 
         if object_count == 0:
             if verbosity > 0:
-                print "No fixtures found."
+                self.stdout.write("No fixtures found.\n")
         else:
             if verbosity > 0:
-                print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count)
+                self.stdout.write("Installed %d object(s) from %d fixture(s)\n" % (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

+ 15 - 8
docs/howto/custom-management-commands.txt

@@ -8,7 +8,7 @@ Writing custom django-admin commands
 
 Applications can register their own actions with ``manage.py``. For example,
 you might want to add a ``manage.py`` action for a Django app that you're
-distributing. In this document, we will be building a custom ``closepoll`` 
+distributing. In this document, we will be building a custom ``closepoll``
 command for the ``polls`` application from the
 :ref:`tutorial<intro-tutorial01>`.
 
@@ -62,9 +62,16 @@ look like this:
                 poll.opened = False
                 poll.save()
 
-                print 'Successfully closed poll "%s"' % poll_id
+                self.stdout.write('Successfully closed poll "%s"\n' % poll_id)
 
-The new custom command can be called using ``python manage.py closepoll 
+.. note::
+    When you are using management commands and wish to provide console
+    output, you should write to ``self.stdout`` and ``self.stderr``,
+    instead of printing to ``stdout`` and ``stderr`` directly. By
+    using these proxies, it becomes much easier to test your custom
+    command.
+
+The new custom command can be called using ``python manage.py closepoll
 <poll_id>``.
 
 The ``handle()`` method takes zero or more ``poll_ids`` and sets ``poll.opened``
@@ -91,8 +98,8 @@ must be added to :attr:`~BaseCommand.option_list` like this:
             )
         # ...
 
-In addition to being able to add custom command line options, all 
-:ref:`management commands<ref-django-admin>` can accept some 
+In addition to being able to add custom command line options, all
+:ref:`management commands<ref-django-admin>` can accept some
 default options such as :djadminopt:`--verbosity` and :djadminopt:`--traceback`.
 
 Command objects
@@ -113,7 +120,7 @@ Subclassing the :class:`BaseCommand` class requires that you implement the
 Attributes
 ----------
 
-All attributes can be set in your derived class and can be used in 
+All attributes can be set in your derived class and can be used in
 :class:`BaseCommand`'s :ref:`subclasses<ref-basecommand-subclasses>`.
 
 .. attribute:: BaseCommand.args
@@ -133,7 +140,7 @@ All attributes can be set in your derived class and can be used in
 .. attribute:: BaseCommand.help
 
   A short description of the command, which will be printed in the
-  help message when the user runs the command 
+  help message when the user runs the command
   ``python manage.py help <command>``.
 
 .. attribute:: BaseCommand.option_list
@@ -230,7 +237,7 @@ Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement
 A command which takes no arguments on the command line.
 
 Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement
-:meth:`~NoArgsCommand.handle_noargs`; :meth:`~BaseCommand.handle` itself is 
+:meth:`~NoArgsCommand.handle_noargs`; :meth:`~BaseCommand.handle` itself is
 overridden to ensure no arguments are passed to the command.
 
 .. method:: NoArgsCommand.handle_noargs(**options)

File diff suppressed because it is too large
+ 0 - 100
tests/modeltests/fixtures/models.py


File diff suppressed because it is too large
+ 146 - 0
tests/modeltests/fixtures/tests.py


Some files were not shown because too many files changed in this diff