south / south / hacks /

Hacks for the Django 1.0/1.0.2 releases.

from django.conf import settings
from django.db.backends.creation import BaseDatabaseCreation
from django.db.models.loading import cache
from django.core import management
from import Command as FlushCommand
from django.utils.datastructures import SortedDict

from south.utils.py3 import string_types

class SkipFlushCommand(FlushCommand):
    def handle_noargs(self, **options):
        # no-op to avoid calling flush

class Hacks:
    def set_installed_apps(self, apps):
        Sets Django's INSTALLED_APPS setting to be effectively the list passed in.
        # Make sure it's a list.
        apps = list(apps)
        # Make sure it contains strings
        if apps:
            assert isinstance(apps[0], string_types), "The argument to set_installed_apps must be a list of strings."
        # Monkeypatch in!
        settings.INSTALLED_APPS, settings.OLD_INSTALLED_APPS = (
    def reset_installed_apps(self):
        Undoes the effect of set_installed_apps.
        settings.INSTALLED_APPS = settings.OLD_INSTALLED_APPS
    def _redo_app_cache(self):
        Used to repopulate AppCache after fiddling with INSTALLED_APPS.
        cache.loaded = False
        cache.handled = {}
        cache.postponed = []
        cache.app_store = SortedDict()
        cache.app_models = SortedDict()
        cache.app_errors = {}
    def clear_app_cache(self):
        Clears the contents of AppCache to a blank state, so new models
        from the ORM can be added.
        self.old_app_models, cache.app_models = cache.app_models, {}
    def unclear_app_cache(self):
        Reversed the effects of clear_app_cache.
        cache.app_models = self.old_app_models
        cache._get_models_cache = {}
    def repopulate_app_cache(self):
        Rebuilds AppCache with the real model definitions.

    def store_app_cache_state(self):
        self.stored_app_cache_state = dict(**cache.__dict__)

    def restore_app_cache_state(self):
        cache.__dict__ = self.stored_app_cache_state

    def patch_flush_during_test_db_creation(self):
        Patches BaseDatabaseCreation.create_test_db to not flush database

        def patch(f):
            def wrapper(*args, **kwargs):
                # hold onto the original and replace flush command with a no-op
                original_flush_command = management._commands['flush']
                    management._commands['flush'] = SkipFlushCommand()
                    # run create_test_db
                    f(*args, **kwargs)
                    # unpatch flush back to the original
                    management._commands['flush'] = original_flush_command
            return wrapper
        BaseDatabaseCreation.create_test_db = patch(BaseDatabaseCreation.create_test_db)