Пример #1
0
def get_migration_abspath(app_label, migration_name):
    from django.db.migrations.loader import MigrationLoader

    if django.VERSION >= (1, 11):
        module_name, _ = MigrationLoader.migrations_module(app_label)
    else:
        module_name = MigrationLoader.migrations_module(app_label)

    migration_path = "{}.{}".format(module_name, migration_name)
    migration_module = import_module(migration_path)

    migration_file = migration_module.__file__
    if migration_file.endswith(".pyc"):
        migration_file = migration_file[:-1]
    return migration_file
Пример #2
0
    def path(self):
        migrations_package_name = MigrationLoader.migrations_module(self.migration.app_label)
        # See if we can import the migrations module directly
        try:
            migrations_module = import_module(migrations_package_name)

            # Python 3 fails when the migrations directory does not have a
            # __init__.py file
            if not hasattr(migrations_module, '__file__'):
                raise ImportError

            basedir = os.path.dirname(upath(migrations_module.__file__))
        except ImportError:
            app_config = apps.get_app_config(self.migration.app_label)
            migrations_package_basename = migrations_package_name.split(".")[-1]

            # Alright, see if it's a direct submodule of the app
            if '%s.%s' % (app_config.name, migrations_package_basename) == migrations_package_name:
                basedir = os.path.join(app_config.path, migrations_package_basename)
            else:
                # In case of using MIGRATION_MODULES setting and the custom
                # package doesn't exist, create one.
                package_dirs = migrations_package_name.split(".")
                create_path = os.path.join(upath(sys.path[0]), *package_dirs)
                if not os.path.isdir(create_path):
                    os.makedirs(create_path)
                for i in range(1, len(package_dirs) + 1):
                    init_dir = os.path.join(upath(sys.path[0]), *package_dirs[:i])
                    init_path = os.path.join(init_dir, "__init__.py")
                    if not os.path.isfile(init_path):
                        open(init_path, "w").close()
                return os.path.join(create_path, self.filename)
        return os.path.join(basedir, self.filename)
Пример #3
0
    def basedir(self):
        migrations_package_name = MigrationLoader.migrations_module(
            self.migration.app_label)

        if migrations_package_name is None:
            raise ValueError(
                "Django can't create migrations for app '%s' because "
                "migrations have been disabled via the MIGRATION_MODULES "
                "setting." % self.migration.app_label)

        # See if we can import the migrations module directly
        try:
            migrations_module = import_module(migrations_package_name)
        except ImportError:
            pass
        else:
            try:
                return upath(module_dir(migrations_module))
            except ValueError:
                pass

        # Alright, see if it's a direct submodule of the app
        app_config = apps.get_app_config(self.migration.app_label)
        maybe_app_name, _, migrations_package_basename = migrations_package_name.rpartition(
            ".")
        if app_config.name == maybe_app_name:
            return os.path.join(app_config.path, migrations_package_basename)

        # In case of using MIGRATION_MODULES setting and the custom package
        # doesn't exist, create one, starting from an existing package
        existing_dirs, missing_dirs = migrations_package_name.split("."), []
        while existing_dirs:
            missing_dirs.insert(0, existing_dirs.pop(-1))
            try:
                base_module = import_module(".".join(existing_dirs))
            except ImportError:
                continue
            else:
                try:
                    base_dir = upath(module_dir(base_module))
                except ValueError:
                    continue
                else:
                    break
        else:
            raise ValueError(
                "Could not locate an appropriate location to create "
                "migrations package %s. Make sure the toplevel "
                "package exists and can be imported." %
                migrations_package_name)

        final_dir = os.path.join(base_dir, *missing_dirs)
        if not os.path.isdir(final_dir):
            os.makedirs(final_dir)
        for missing_dir in missing_dirs:
            base_dir = os.path.join(base_dir, missing_dir)
            with open(os.path.join(base_dir, "__init__.py"), "w"):
                pass

        return final_dir
def get_installed_app_labels_with_migrations():
    """ Get the app labels, because settings.INSTALLED_APPS doesn't necessarily give us the labels.
        Remove django.contrib.contenttypes because we want it to run before us.
        Return list of tuples like ('admin', '__first__')
    """
    from django.apps import apps
    apps_with_migrations = []
    for app in apps.get_app_configs():
        if app.label == 'contenttypes':
            continue  # Ignore the contenttypes app

        migrations_module = MigrationLoader.migrations_module(app.label)
        try:
            # Django 1.11 changed the return value of the migrations_module call to a 2-element
            # tuple.  The actual module is the first entry
            if isinstance(migrations_module, tuple):
                migrations_module = migrations_module[0]

            module = import_module(migrations_module)
        except ImportError:
            continue

        if not hasattr(module, "__path__"):
            continue

        # Make sure there are python files in the migration folder (other than the init file)
        has_files = any(x for x in os.listdir(module.__path__[0])
                        if x.endswith(".py") and x != "__init__.py")
        if not has_files:
            continue

        apps_with_migrations.append(app.label)

    return [(x, '__first__') for x in apps_with_migrations]
def get_installed_app_labels_with_migrations():
    """ Get the app labels, because settings.INSTALLED_APPS doesn't necessarily give us the labels.
        Remove django.contrib.contenttypes because we want it to run before us.
        Return list of tuples like ('admin', '__first__')
    """
    from django.apps import apps
    apps_with_migrations = []
    for app in apps.get_app_configs():
        if app.label == 'contenttypes':
            continue  # Ignore the contenttypes app

        migrations_module = MigrationLoader.migrations_module(app.label)
        try:
            # Django 1.11 changed the return value of the migrations_module call to a 2-element
            # tuple.  The actual module is the first entry
            if isinstance(migrations_module, tuple):
                migrations_module = migrations_module[0]

            module = import_module(migrations_module)
        except ImportError:
            continue

        if not hasattr(module, "__path__"):
            continue

        # Make sure there are python files in the migration folder (other than the init file)
        has_files = any(
            x for x in os.listdir(module.__path__[0]) if x.endswith(".py") and x != "__init__.py"
        )
        if not has_files:
            continue

        apps_with_migrations.append(app.label)

    return [(x, '__first__') for x in apps_with_migrations]
Пример #6
0
def get_installed_app_labels_with_migrations():
    """ Get the app labels, because settings.INSTALLED_APPS doesn't necessarily give us the labels. 
        Remove django.contrib.contenttypes because we want it to run before us. 
        Return list of tuples like ('admin', '__first__') 
    """
    from django.apps import apps
    apps_with_migrations = []
    for app in apps.get_app_configs():
        if app.label == 'contenttypes': continue # Ignore the contenttypes app

        migrations_module = MigrationLoader.migrations_module(app.label)
        try:
            module = import_module(migrations_module)
        except ImportError:
            continue

        if not hasattr(module, "__path__"):
            continue

        # Make sure there are python files in the migration folder
        has_files = bool(x for x in os.listdir(module.__path__[0]) if x.endswith(".py"))
        if not has_files:
            continue

        apps_with_migrations.append(app.label)

    return [(x, '__first__') for x in apps_with_migrations]
Пример #7
0
def _get_migrations(included_apps):
    """
    Get migrations for included apps.
    """
    migration_objects = []

    for app_config in apps.get_app_configs():
        if app_config.name not in included_apps:
            continue
        app_label = app_config.label
        module_name, _ = MigrationLoader.migrations_module(app_label)

        if module_name is None:
            continue

        try:
            module = import_module(module_name)
        except ImportError:
            continue

        directory = os.path.dirname(module.__file__)
        for name in os.listdir(directory):
            if name.endswith(".py"):
                import_name = name.rsplit(".", 1)[0]
                if import_name[0] not in "_.~":
                    migration_objects.append(
                        MigrationRecorder.Migration(app=app_label,
                                                    name=import_name))
    return migration_objects
Пример #8
0
    def path(self):
        migrations_package_name = MigrationLoader.migrations_module(self.migration.app_label)
        # See if we can import the migrations module directly
        try:
            migrations_module = import_module(migrations_package_name)

            # Python 3 fails when the migrations directory does not have a
            # __init__.py file
            if not hasattr(migrations_module, '__file__'):
                raise ImportError

            basedir = os.path.dirname(upath(migrations_module.__file__))
        except ImportError:
            app_config = apps.get_app_config(self.migration.app_label)
            migrations_package_basename = migrations_package_name.split(".")[-1]

            # Alright, see if it's a direct submodule of the app
            if '%s.%s' % (app_config.name, migrations_package_basename) == migrations_package_name:
                basedir = os.path.join(app_config.path, migrations_package_basename)
            else:
                # In case of using MIGRATION_MODULES setting and the custom
                # package doesn't exist, create one.
                package_dirs = migrations_package_name.split(".")
                create_path = os.path.join(upath(sys.path[0]), *package_dirs)
                if not os.path.isdir(create_path):
                    os.makedirs(create_path)
                for i in range(1, len(package_dirs) + 1):
                    init_dir = os.path.join(upath(sys.path[0]), *package_dirs[:i])
                    init_path = os.path.join(init_dir, "__init__.py")
                    if not os.path.isfile(init_path):
                        open(init_path, "w").close()
                return os.path.join(create_path, self.filename)
        return os.path.join(basedir, self.filename)
Пример #9
0
    def basedir(self):
        migrations_package_name = MigrationLoader.migrations_module(self.migration.app_label)

        if migrations_package_name is None:
            raise ValueError(
                "Django can't create migrations for app '%s' because "
                "migrations have been disabled via the MIGRATION_MODULES "
                "setting." % self.migration.app_label
            )

        # See if we can import the migrations module directly
        try:
            migrations_module = import_module(migrations_package_name)
        except ImportError:
            pass
        else:
            try:
                return upath(module_dir(migrations_module))
            except ValueError:
                pass

        # Alright, see if it's a direct submodule of the app
        app_config = apps.get_app_config(self.migration.app_label)
        maybe_app_name, _, migrations_package_basename = migrations_package_name.rpartition(".")
        if app_config.name == maybe_app_name:
            return os.path.join(app_config.path, migrations_package_basename)

        # In case of using MIGRATION_MODULES setting and the custom package
        # doesn't exist, create one, starting from an existing package
        existing_dirs, missing_dirs = migrations_package_name.split("."), []
        while existing_dirs:
            missing_dirs.insert(0, existing_dirs.pop(-1))
            try:
                base_module = import_module(".".join(existing_dirs))
            except ImportError:
                continue
            else:
                try:
                    base_dir = upath(module_dir(base_module))
                except ValueError:
                    continue
                else:
                    break
        else:
            raise ValueError(
                "Could not locate an appropriate location to create "
                "migrations package %s. Make sure the toplevel "
                "package exists and can be imported." %
                migrations_package_name)

        final_dir = os.path.join(base_dir, *missing_dirs)
        if not os.path.isdir(final_dir):
            os.makedirs(final_dir)
        for missing_dir in missing_dirs:
            base_dir = os.path.join(base_dir, missing_dir)
            with open(os.path.join(base_dir, "__init__.py"), "w"):
                pass

        return final_dir
Пример #10
0
    def __init__(self, app_label, do_reload=False):
        self.app_label = app_label

        # Some logic duplicated from MigrationLoader.load_disk, but avoiding
        # loading all migrations since that's relatively slow.
        self.migrations_module_name, _explicit = MigrationLoader.migrations_module(
            app_label)
        try:
            self.migrations_module = import_module(self.migrations_module_name)
        except ModuleNotFoundError:
            # Unmigrated app
            self.migrations_module = None
        else:
            if do_reload:
                reload(self.migrations_module)
Пример #11
0
    def path(self):
        migrations_package_name = MigrationLoader.migrations_module(self.migration.app_label)
        # See if we can import the migrations module directly
        try:
            migrations_module = import_module(migrations_package_name)
            basedir = os.path.dirname(migrations_module.__file__)
        except ImportError:
            app_config = apps.get_app_config(self.migration.app_label)
            migrations_package_basename = migrations_package_name.split(".")[-1]

            # Alright, see if it's a direct submodule of the app
            if '%s.%s' % (app_config.name, migrations_package_basename) == migrations_package_name:
                basedir = os.path.join(app_config.path, migrations_package_basename)
            else:
                raise ImportError("Cannot open migrations module %s for app %s" % (migrations_package_name, self.migration.app_label))
        return os.path.join(basedir, self.filename)
Пример #12
0
 def path(self):
     migrations_module_name = MigrationLoader.migrations_module(self.migration.app_label)
     app_module = cache.get_app(self.migration.app_label)
     # See if we can import the migrations module directly
     try:
         migrations_module = import_module(migrations_module_name)
         basedir = os.path.dirname(migrations_module.__file__)
     except ImportError:
         # Alright, see if it's a direct submodule of the app
         oneup = ".".join(migrations_module_name.split(".")[:-1])
         app_oneup = ".".join(app_module.__name__.split(".")[:-1])
         if oneup == app_oneup:
             basedir = os.path.join(os.path.dirname(app_module.__file__), migrations_module_name.split(".")[-1])
         else:
             raise ImportError("Cannot open migrations module %s for app %s" % (migrations_module_name, self.migration.app_label))
     return os.path.join(basedir, self.filename)
Пример #13
0
    def path(self):
        migrations_package_name = MigrationLoader.migrations_module(self.migration.app_label)
        # See if we can import the migrations module directly
        try:
            migrations_module = import_module(migrations_package_name)
            basedir = os.path.dirname(migrations_module.__file__)
        except ImportError:
            app_config = apps.get_app_config(self.migration.app_label)
            migrations_package_basename = migrations_package_name.split(".")[-1]

            # Alright, see if it's a direct submodule of the app
            if '%s.%s' % (app_config.name, migrations_package_basename) == migrations_package_name:
                basedir = os.path.join(app_config.path, migrations_package_basename)
            else:
                raise ImportError("Cannot open migrations module %s for app %s" % (migrations_package_name, self.migration.app_label))
        return os.path.join(basedir, self.filename)
Пример #14
0
 def path(self):
     migrations_module_name = MigrationLoader.migrations_module(self.migration.app_label)
     app_module = cache.get_app(self.migration.app_label)
     # See if we can import the migrations module directly
     try:
         migrations_module = import_module(migrations_module_name)
         basedir = os.path.dirname(migrations_module.__file__)
     except ImportError:
         # Alright, see if it's a direct submodule of the app
         oneup = ".".join(migrations_module_name.split(".")[:-1])
         app_oneup = ".".join(app_module.__name__.split(".")[:-1])
         if oneup == app_oneup:
             basedir = os.path.join(os.path.dirname(app_module.__file__), migrations_module_name.split(".")[-1])
         else:
             raise ImportError("Cannot open migrations module %s for app %s" % (migrations_module_name, self.migration.app_label))
     return os.path.join(basedir, self.filename)
Пример #15
0
def check_migrations(app_configs, **kwargs):
    if app_configs is None:
        app_configs = apps.get_app_configs()
    errors = []
    hint = (
        "Assign an explicit stage to it, break its operation into multiple "
        "migrations if it's not already applied or define an explicit stage for "
        "it using `MIGRATION_STAGE_OVERRIDE` or `MIGRATION_STAGE_FALLBACK` if the "
        "migration is not under your control.")
    for app_config in app_configs:
        # Most of the following code is taken from MigrationLoader.load_disk
        # while allowing non-global app_configs to be used.
        module_name, _explicit = MigrationLoader.migrations_module(
            app_config.label)
        if module_name is None:  # pragma: no cover
            continue
        try:
            module = import_module(module_name)
        except ImportError:
            # This is not the place to deal with migration issues.
            continue
        directory = os.path.dirname(module.__file__)
        migration_names = set()
        for name in os.listdir(directory):
            if name.endswith(".py"):
                import_name = name.rsplit(".", 1)[0]
                migration_names.add(import_name)
        for migration_name in migration_names:
            try:
                migration_class = import_string(
                    f"{module_name}.{migration_name}.Migration")
            except ImportError:
                # This is not the place to deal with migration issues.
                continue
            migration = migration_class(migration_name, app_config.label)
            try:
                must_post_deploy_migration(migration)
            except ValueError as e:
                errors.append(
                    Error(
                        str(e),
                        hint=hint,
                        obj=(migration.app_label, migration.name),
                        id="migrations.0001",
                    ))
    return errors
    def __init__(self, name, app_label):
        # by changing app_label here to 'wagtailcore' we trick Django migrations system
        # to think that this migration belongs to wagtailcore app
        # this is necessary to make model name resolution work
        app_label = 'wagtailcore'
        super(Migration, self).__init__(name, app_label)

        # find last wagtailcore migration
        mod_name = MigrationLoader.migrations_module(app_label)
        if DJANGO_VERSION >= (1, 11):
            # Django 1.11 returns tuple(str, bool) while older versions return str
            mod_name = mod_name[0]
        mod = import_module(mod_name)
        migrations = []
        # this loop acts the same way as MigrationLoader.
        for name in os.listdir(os.path.dirname(mod.__file__)):
            if not name.endswith('.py'):
                continue
            import_name = name.rsplit('.', 1)[0]
            if import_name[0] in '_.~':
                continue
            migrations.append(import_name)
        last_migration = sorted(migrations, reverse=True)[0]
        # By using `replaces` we make sure that this migration doesn't have ambiguous `app_label`.
        # When this migration is applied Django writes only replaced migration
        # to django_migrations table in DB. Otherwise migration would have
        # 'wagtailtranslation' as app_label in django_migrations table and
        # `migrate` command would consider this migration as unapplied due
        # to app_label mismatch.
        self.replaces = [
            (app_label, last_migration),
        ]

        # import operations from wagtail migration we are replacing
        # and prepend them to operations of this migration
        mod_path = '{}.{}'.format(mod_name, last_migration)
        orig_migration = import_module(mod_path).Migration
        self.operations[:0] = orig_migration.operations
        self.dependencies = orig_migration.dependencies
class Command(MakeMigrationsCommand):
    option_list = BaseCommand.option_list

    def handle(self, *app_labels, **options):
        self.verbosity = int(options.get('verbosity'))
        self.interactive = options.get('interactive')
        self.dry_run = False

        self.loader = MigrationLoader(None, ignore_no_migrations=True)

        for app_label in app_labels:
            self.handle_app(app_label)

    def handle_app(self, app_label):
        app = apps.get_app_config(app_label)
        self.convert(app)

    def convert(self, app):
        print('Processing %s' % app.label)

        if not self.has_south_migrations(app) and not self.has_initial_data_outside_of_migrations(app):
            print('App %s is already migrated to new style migrations' % app.label)
            return True

        if self.has_south_migrations(app):
            self.remove_migrations(app)

        self.create_new_migrations(app)

        if self.has_initial_data_outside_of_migrations(app):
            print('Found initial_data outside of migrations')
            self.create_data_migration_from_initial_data(app)

    def has_south_migrations(self, app):
        """ Apps with South migrations are in both sets"""
        return (app.label in self.loader.unmigrated_apps and
                app.label in self.loader.migrated_apps)

    def has_initial_data_outside_of_migrations(self, app):
        # Are there any initial_data fixtures
        if not self.get_initial_data_fixtures(app):
            return False

        # Check if initial data is already inside migration
        leaf_nodes = self.loader.graph.leaf_nodes(app.label)
        if not leaf_nodes:
            return True
        _, migration_name = leaf_nodes[0]
        migration_string = open(os.path.join(self.get_migrations_dir(app), migration_name + '.py')).read()
        if "call_command('loaddata'" in migration_string:
            return False

        return True

    def get_migrations_dir(self, app):
        module_name = self.loader.migrations_module(app.label)
        module = import_module(module_name)
        return os.path.dirname(module.__file__)

    def get_initial_data_fixtures(self, app):
        fixture_dir = os.path.join(app.path, 'fixtures')
        return list(glob.iglob(os.path.join(fixture_dir, 'initial_data.*')))

    def remove_migrations(self, app):
        print('    Removing old South migrations')
        directory = self.get_migrations_dir(app)
        for name in os.listdir(directory):
            if (name.endswith('.py') or name.endswith('.pyc'))and name != '__init__.py':
                print('      Deleting %s %s' % (name, '(fake)' if self.dry_run else ''))
                if not self.dry_run:
                    os.remove(os.path.join(directory, name))

    def create_new_migrations(self, app):
        call_command('makemigrations', app.label, dry_run=self.dry_run, verbosity=self.verbosity)

    def create_data_migration_from_initial_data(self, app):
        # Create empty migration
        call_command('makemigrations', app.label, empty=True, dry_run=self.dry_run, verbosity=self.verbosity)

        # Get latest migration
        self.loader.build_graph()
        _, migration_name = self.loader.graph.leaf_nodes(app.label)[0]

        # Find the file
        directory = self.get_migrations_dir(app)
        empty_migration_file = os.path.join(directory, migration_name + '.py')

        # Inject code
        migration_string = open(empty_migration_file).read()
        callable_code = RUN_CODE % (
            ', '.join(map(lambda fixture_name: '"%s"' % os.path.basename(fixture_name),
                          self.get_initial_data_fixtures(app))),
            app.label
        )
        migration_string = (migration_string.replace('class Migration', callable_code + 'class Migration')
                                            .replace('operations = [', 'operations = [' + OPERATIONS))
        with open(empty_migration_file, "wb") as fh:
            fh.write(migration_string.encode('utf-8'))

        # wipe *.pyc
        try:
            os.remove(os.path.join(directory,  os.path.join(directory, migration_name + '.pyc')))
        except OSError:
            pass
Пример #18
0
from __future__ import unicode_literals