def test_fixture_and_other_outputs_mixed(self):
     output = "Loading 'foobar' fixtures...\n" \
         "Checking /tmp/what/no for fixtures...\n" \
         "Installed 37 object(s) from 1 fixture(s)\n" \
         "Ha ha ha ha halibut.\n"
     object_count, fixture_count, other_msgs = process_django_output(output)
     self.assertEqual(object_count, 37)
     self.assertEqual(fixture_count, 1)
     self.assertEqual(len(other_msgs), 3)
 def test_multiple_fixture_output(self):
     # Include one line of alternate format output, from which we don't
     # actually bother extracting the extra information yet.
     output = "Installed 2 object(s) from 1 fixture(s)\n" \
         "Installed 4 object(s) from 1 fixture(s)\n" \
         "Installed 7 object(s) from 2 fixture(s)\n" \
         "Installed 4 object(s) (of 6) from 1 fixture(s)\n"
     object_count, fixture_count, other_msgs = process_django_output(output)
     self.assertEqual(object_count, 17)
     self.assertEqual(fixture_count, 5)
     self.assertEqual(len(other_msgs), 0)
Esempio n. 3
0
    def handle(self, *fixture_labels, **options):
        using = options.get('database', DEFAULT_DB_ALIAS)
        connection = connections[using]
        self.style = no_style()
        show_traceback = options.get('traceback', False)
        commit = options.get('commit', True)

        # I'm sure there is a valid reason why Django's loaddata does this,
        # so I'm just going to replicate its behaviour.
        cursor = connection.cursor()

        if commit:
            transaction.commit_unless_managed(using=using)
            transaction.enter_transaction_management(using=using)
            transaction.managed(True, using=using)

        total_object_count = 0
        total_fixture_count = 0
        do_initial_data = False
        captured_outputs = []
        original_verbosity = int(options.get('verbosity'))
        # Mark this loaddata run as a special case for syncdb loading.
        # Django's loaddata will be run first, ours second.
        if fixture_labels == ('initial_data',):
            # Assign a special handler type for initial data
            fixture_handlers = [('initial_data', 'both_for_initial', None, None)]
        else:
            # Build a list of (label, handler, type, resolved_object) tuples.
            fixture_handlers = associate_handlers(fixture_labels)

        for label, handler, type_, obj in fixture_handlers:
            if handler in ['django', 'both_for_initial']:
                captured_stdout = StringIO()
                # Need to assign manually; normally available to handle() via
                # BaseCommand.execute(), but not when we're using it this way.
                DjangoLoaddata.stdout = captured_stdout
                DjangoLoaddata.stderr = self.stderr
                # Capturing fixture counts from stdout requires forcing the
                # verbosity option to a minimum of 1. If set higher by the
                # user, respect that. Collect any extra messages for display.
                if 'verbosity' in options:
                    options['verbosity'] = 1 if options['verbosity'] == 0 else options['verbosity']
                else:
                    options['verbosity'] = 1
                # We will either be in our own transaction handling or that of
                # the script that called us, so disable transaction management
                # inside Django's loaddata
                options['commit'] = False
                try:
                    if 'database' not in options:
                        options.update({'database': using})
                    DjangoLoaddata.handle(label, **options)
                except Exception:
                    if commit:
                        transaction.rollback(using=using)
                        transaction.leave_transaction_management(using=using)
                    raise
                django_object_count, django_fixture_count, other_msgs = process_django_output(captured_stdout.getvalue())
                captured_stdout.close()
                total_object_count += django_object_count
                total_fixture_count += django_fixture_count
                captured_outputs.extend(other_msgs)

            if handler in ['class_fixtures', 'both_for_initial']:
                if type_ == 'instance':
                    fixtures = [label]
                elif type_ == 'module':
                    fixtures = get_fixtures_from_module(label)
                elif type_ == 'submodule_name':
                    # obj is a reference to an individual submodule of
                    # the fixtures package of some app.
                    fixtures = get_fixtures_from_module(obj)
                elif type_ == 'app_label':
                    # obj is a reference to the fixtures package of the
                    # app named in the label. Load all the fixture modules
                    # contained within, excluding initial_data.
                    fixtures = []
                    for importer, module_name, is_pkg in walk_packages(obj.__path__):
                        if module_name == 'initial_data':
                            continue
                        submodule = importer.find_module(module_name).load_module(module_name)
                        submod_fixtures = get_fixtures_from_module(submodule)
                        for submod_fixture in submod_fixtures:
                            # In case the user has a deeper submodule hierarchy in place
                            # with fixtures imported from submodule to submodule, make sure no fixture
                            # is included in the list twice through submodule discovery.
                            if submod_fixture not in fixtures:
                                fixtures.append(submod_fixture)
                elif type_ is None and label == 'initial_data':
                    fixtures = gather_initial_data_fixtures()

                try:
                    saved_set = set()
                    for fixture in fixtures:
                        saved_objects = fixture.load(using=using)
                        for obj in saved_objects.items():
                            saved_set.add(obj)
                        total_fixture_count += 1
                    total_object_count += len(saved_set)
                except (SystemExit, KeyboardInterrupt):
                    raise
                except Exception:
                    import traceback
                    if commit:
                        transaction.rollback(using=using)
                        transaction.leave_transaction_management(using=using)
                    if show_traceback:
                        traceback.print_exc()
                    else:
                        self.stderr.write(
                            self.style.ERROR("Problem installing class-based fixtures: %s" %
                            ''.join(traceback.format_exception(sys.exc_type,
                                 sys.exc_value, sys.exc_traceback))))
                    return
        if commit:
            transaction.commit(using=using)
            transaction.leave_transaction_management(using=using)

        # Same MySQL workaround as in Django's loaddata
        if commit:
            connection.close()

        if total_fixture_count == 0:
            if original_verbosity >= 1:
                self.stdout.write("No fixtures found.\n")
        else:
            if original_verbosity >= 2 and captured_outputs:
                # Prevent printing Django's result row along with our own
                # when both handlers activate but only class-based fixtures
                # are found.
                if captured_outputs[-1].startswith('No fixtures found.'):
                    captured_outputs = captured_outputs[:-1]
                self.stdout.write('\n'.join(captured_outputs) + '\n')
            if original_verbosity >= 1:
                # The original loaddata has another possible output format
                # used when less objects were loaded than were present in the
                # fixtures, but I don't care enough to implement it.
                self.stdout.write("Installed %d object(s) from %d fixture(s)\n" %
                    (total_object_count, total_fixture_count))
 def test_single_fixture_output(self):
     output = "Installed 2 object(s) from 1 fixture(s)\n"
     object_count, fixture_count, other_msgs = process_django_output(output)
     self.assertEqual(object_count, 2)
     self.assertEqual(fixture_count, 1)
     self.assertEqual(len(other_msgs), 0)