diff options
author | ttt | 2017-05-13 00:29:47 +0530 |
---|---|---|
committer | ttt | 2017-05-13 00:29:47 +0530 |
commit | abf599be33b383a6a5baf9493093b2126a622ac8 (patch) | |
tree | 4c5ab6e0d935d5e65fabcf0258e4a00dd20a5afa /lib/python2.7/site-packages/south/management | |
download | SBHS-2018-Rpi-abf599be33b383a6a5baf9493093b2126a622ac8.tar.gz SBHS-2018-Rpi-abf599be33b383a6a5baf9493093b2126a622ac8.tar.bz2 SBHS-2018-Rpi-abf599be33b383a6a5baf9493093b2126a622ac8.zip |
added all server files
Diffstat (limited to 'lib/python2.7/site-packages/south/management')
12 files changed, 1061 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/south/management/__init__.py b/lib/python2.7/site-packages/south/management/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/python2.7/site-packages/south/management/__init__.py diff --git a/lib/python2.7/site-packages/south/management/commands/__init__.py b/lib/python2.7/site-packages/south/management/commands/__init__.py new file mode 100644 index 0000000..da218eb --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/__init__.py @@ -0,0 +1,40 @@ + +# Common framework for syncdb actions + +import copy + +from django.core import management +from django.conf import settings + +# Make sure the template loader cache is fixed _now_ (#448) +import django.template.loaders.app_directories + +from south.hacks import hacks +from south.management.commands.syncdb import Command as SyncCommand + +class MigrateAndSyncCommand(SyncCommand): + """Used for situations where "syncdb" is called by test frameworks.""" + + option_list = copy.deepcopy(SyncCommand.option_list) + + for opt in option_list: + if "--migrate" == opt.get_opt_string(): + opt.default = True + break + +def patch_for_test_db_setup(): + # Load the commands cache + management.get_commands() + # Repoint to the correct version of syncdb + if hasattr(settings, "SOUTH_TESTS_MIGRATE") and not settings.SOUTH_TESTS_MIGRATE: + # point at the core syncdb command when creating tests + # tests should always be up to date with the most recent model structure + management._commands['syncdb'] = 'django.core' + else: + management._commands['syncdb'] = MigrateAndSyncCommand() + # Avoid flushing data migrations. + # http://code.djangoproject.com/ticket/14661 introduced change that flushed custom + # sql during the test database creation (thus flushing the data migrations). + # we patch flush to be no-op during create_test_db, but still allow flushing + # after each test for non-transactional backends. + hacks.patch_flush_during_test_db_creation() diff --git a/lib/python2.7/site-packages/south/management/commands/convert_to_south.py b/lib/python2.7/site-packages/south/management/commands/convert_to_south.py new file mode 100644 index 0000000..658ed48 --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/convert_to_south.py @@ -0,0 +1,95 @@ +""" +Quick conversion command module. +""" + +from __future__ import print_function + +from optparse import make_option +import sys + +from django.core.management.base import BaseCommand +from django.core.management.color import no_style +from django.conf import settings +from django.db import models +from django.core import management +from django.core.exceptions import ImproperlyConfigured + +from south.migration import Migrations +from south.hacks import hacks +from south.exceptions import NoMigrations + +class Command(BaseCommand): + + option_list = BaseCommand.option_list + if '--verbosity' not in [opt.get_opt_string() for opt in BaseCommand.option_list]: + option_list += ( + make_option('--verbosity', action='store', dest='verbosity', default='1', + type='choice', choices=['0', '1', '2'], + help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'), + ) + option_list += ( + make_option('--delete-ghost-migrations', action='store_true', dest='delete_ghosts', default=False, + help="Tells South to delete any 'ghost' migrations (ones in the database but not on disk)."), + make_option('--ignore-ghost-migrations', action='store_true', dest='ignore_ghosts', default=False, + help="Tells South to ignore any 'ghost' migrations (ones in the database but not on disk) and continue to apply new migrations."), + ) + + help = "Quickly converts the named application to use South if it is currently using syncdb." + + def handle(self, app=None, *args, **options): + + # Make sure we have an app + if not app: + print("Please specify an app to convert.") + return + + # See if the app exists + app = app.split(".")[-1] + try: + app_module = models.get_app(app) + except ImproperlyConfigured: + print("There is no enabled application matching '%s'." % app) + return + + # Try to get its list of models + model_list = models.get_models(app_module) + if not model_list: + print("This application has no models; this command is for applications that already have models syncdb'd.") + print("Make some models, and then use ./manage.py schemamigration %s --initial instead." % app) + return + + # Ask South if it thinks it's already got migrations + try: + Migrations(app) + except NoMigrations: + pass + else: + print("This application is already managed by South.") + return + + # Finally! It seems we've got a candidate, so do the two-command trick + verbosity = int(options.get('verbosity', 0)) + management.call_command("schemamigration", app, initial=True, verbosity=verbosity) + + # Now, we need to re-clean and sanitise appcache + hacks.clear_app_cache() + hacks.repopulate_app_cache() + + # And also clear our cached Migration classes + Migrations._clear_cache() + + # Now, migrate + management.call_command( + "migrate", + app, + "0001", + fake=True, + verbosity=verbosity, + ignore_ghosts=options.get("ignore_ghosts", False), + delete_ghosts=options.get("delete_ghosts", False), + ) + + print() + print("App '%s' converted. Note that South assumed the application's models matched the database" % app) + print("(i.e. you haven't changed it since last syncdb); if you have, you should delete the %s/migrations" % app) + print("directory, revert models.py so it matches the database, and try again.") diff --git a/lib/python2.7/site-packages/south/management/commands/datamigration.py b/lib/python2.7/site-packages/south/management/commands/datamigration.py new file mode 100644 index 0000000..c3175e7 --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/datamigration.py @@ -0,0 +1,139 @@ +""" +Data migration creation command +""" + +from __future__ import print_function + +import sys +import os +import re +from optparse import make_option + +try: + set +except NameError: + from sets import Set as set + +from django.core.management.base import BaseCommand +from django.core.management.color import no_style +from django.db import models +from django.conf import settings + +from south.migration import Migrations +from south.exceptions import NoMigrations +from south.creator import freezer + +class Command(BaseCommand): + option_list = BaseCommand.option_list + ( + make_option('--freeze', action='append', dest='freeze_list', type='string', + help='Freeze the specified app(s). Provide an app name with each; use the option multiple times for multiple apps'), + make_option('--stdout', action='store_true', dest='stdout', default=False, + help='Print the migration to stdout instead of writing it to a file.'), + ) + help = "Creates a new template data migration for the given app" + usage_str = "Usage: ./manage.py datamigration appname migrationname [--stdout] [--freeze appname]" + + def handle(self, app=None, name="", freeze_list=None, stdout=False, verbosity=1, **options): + + verbosity = int(verbosity) + + # Any supposed lists that are None become empty lists + freeze_list = freeze_list or [] + + # --stdout means name = - + if stdout: + name = "-" + + # Only allow valid names + if re.search('[^_\w]', name) and name != "-": + self.error("Migration names should contain only alphanumeric characters and underscores.") + + # If not name, there's an error + if not name: + self.error("You must provide a name for this migration.\n" + self.usage_str) + + if not app: + self.error("You must provide an app to create a migration for.\n" + self.usage_str) + + # Ensure that verbosity is not a string (Python 3) + try: + verbosity = int(verbosity) + except ValueError: + self.error("Verbosity must be an number.\n" + self.usage_str) + + # Get the Migrations for this app (creating the migrations dir if needed) + migrations = Migrations(app, force_creation=True, verbose_creation=verbosity > 0) + + # See what filename is next in line. We assume they use numbers. + new_filename = migrations.next_filename(name) + + # Work out which apps to freeze + apps_to_freeze = self.calc_frozen_apps(migrations, freeze_list) + + # So, what's in this file, then? + file_contents = self.get_migration_template() % { + "frozen_models": freezer.freeze_apps_to_string(apps_to_freeze), + "complete_apps": apps_to_freeze and "complete_apps = [%s]" % (", ".join(map(repr, apps_to_freeze))) or "" + } + + # - is a special name which means 'print to stdout' + if name == "-": + print(file_contents) + # Write the migration file if the name isn't - + else: + fp = open(os.path.join(migrations.migrations_dir(), new_filename), "w") + fp.write(file_contents) + fp.close() + print("Created %s." % new_filename, file=sys.stderr) + + def calc_frozen_apps(self, migrations, freeze_list): + """ + Works out, from the current app, settings, and the command line options, + which apps should be frozen. + """ + apps_to_freeze = [] + for to_freeze in freeze_list: + if "." in to_freeze: + self.error("You cannot freeze %r; you must provide an app label, like 'auth' or 'books'." % to_freeze) + # Make sure it's a real app + if not models.get_app(to_freeze): + self.error("You cannot freeze %r; it's not an installed app." % to_freeze) + # OK, it's fine + apps_to_freeze.append(to_freeze) + if getattr(settings, 'SOUTH_AUTO_FREEZE_APP', True): + apps_to_freeze.append(migrations.app_label()) + return apps_to_freeze + + def error(self, message, code=1): + """ + Prints the error, and exits with the given code. + """ + print(message, file=sys.stderr) + sys.exit(code) + + def get_migration_template(self): + return MIGRATION_TEMPLATE + + +MIGRATION_TEMPLATE = """# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + # Note: Don't use "from appname.models import ModelName". + # Use orm.ModelName to refer to models in this application, + # and orm['appname.ModelName'] for models in other applications. + + def backwards(self, orm): + "Write your backwards methods here." + + models = %(frozen_models)s + + %(complete_apps)s + symmetrical = True +""" diff --git a/lib/python2.7/site-packages/south/management/commands/graphmigrations.py b/lib/python2.7/site-packages/south/management/commands/graphmigrations.py new file mode 100644 index 0000000..6ff1e47 --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/graphmigrations.py @@ -0,0 +1,63 @@ +""" +Outputs a graphviz dot file of the dependencies. +""" + +from __future__ import print_function + +from optparse import make_option +import re +import textwrap + +from django.core.management.base import BaseCommand +from django.core.management.color import no_style + +from south.migration import Migrations, all_migrations + +class Command(BaseCommand): + + help = "Outputs a GraphViz dot file of all migration dependencies to stdout." + + def handle(self, **options): + + # Resolve dependencies + Migrations.calculate_dependencies() + + colors = [ 'crimson', 'darkgreen', 'darkgoldenrod', 'navy', + 'brown', 'darkorange', 'aquamarine' , 'blueviolet' ] + color_index = 0 + wrapper = textwrap.TextWrapper(width=40) + + print("digraph G {") + + # Group each app in a subgraph + for migrations in all_migrations(): + print(" subgraph %s {" % migrations.app_label()) + print(" node [color=%s];" % colors[color_index]) + for migration in migrations: + # Munge the label - text wrap and change _ to spaces + label = "%s - %s" % ( + migration.app_label(), migration.name()) + label = re.sub(r"_+", " ", label) + label= "\\n".join(wrapper.wrap(label)) + print(' "%s.%s" [label="%s"];' % ( + migration.app_label(), migration.name(), label)) + print(" }") + color_index = (color_index + 1) % len(colors) + + # For every migration, print its links. + for migrations in all_migrations(): + for migration in migrations: + for other in migration.dependencies: + # Added weight tends to keep migrations from the same app + # in vertical alignment + attrs = "[weight=2.0]" + # But the more interesting edges are those between apps + if other.app_label() != migration.app_label(): + attrs = "[style=bold]" + print(' "%s.%s" -> "%s.%s" %s;' % ( + other.app_label(), other.name(), + migration.app_label(), migration.name(), + attrs + )) + + print("}"); diff --git a/lib/python2.7/site-packages/south/management/commands/migrate.py b/lib/python2.7/site-packages/south/management/commands/migrate.py new file mode 100644 index 0000000..693dbb7 --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/migrate.py @@ -0,0 +1,264 @@ +""" +Migrate management command. +""" + +from __future__ import print_function + +import os.path, re, sys +from functools import reduce +from optparse import make_option + +from django.core.management.base import BaseCommand +from django.conf import settings +from django.utils.importlib import import_module + +from south import migration +from south.migration import Migrations +from south.exceptions import NoMigrations +from south.db import DEFAULT_DB_ALIAS + +class Command(BaseCommand): + option_list = BaseCommand.option_list + ( + make_option('--all', action='store_true', dest='all_apps', default=False, + help='Run the specified migration for all apps.'), + make_option('--list', action='store_true', dest='show_list', default=False, + help='List migrations noting those that have been applied'), + make_option('--changes', action='store_true', dest='show_changes', default=False, + help='List changes for migrations'), + make_option('--skip', action='store_true', dest='skip', default=False, + help='Will skip over out-of-order missing migrations'), + make_option('--merge', action='store_true', dest='merge', default=False, + help='Will run out-of-order missing migrations as they are - no rollbacks.'), + make_option('--no-initial-data', action='store_true', dest='no_initial_data', default=False, + help='Skips loading initial data if specified.'), + make_option('--fake', action='store_true', dest='fake', default=False, + help="Pretends to do the migrations, but doesn't actually execute them."), + make_option('--db-dry-run', action='store_true', dest='db_dry_run', default=False, + help="Doesn't execute the SQL generated by the db methods, and doesn't store a record that the migration(s) occurred. Useful to test migrations before applying them."), + make_option('--delete-ghost-migrations', action='store_true', dest='delete_ghosts', default=False, + help="Tells South to delete any 'ghost' migrations (ones in the database but not on disk)."), + make_option('--ignore-ghost-migrations', action='store_true', dest='ignore_ghosts', default=False, + help="Tells South to ignore any 'ghost' migrations (ones in the database but not on disk) and continue to apply new migrations."), + make_option('--noinput', action='store_false', dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.'), + make_option('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. ' + 'Defaults to the "default" database.'), + ) + if '--verbosity' not in [opt.get_opt_string() for opt in BaseCommand.option_list]: + option_list += ( + make_option('--verbosity', action='store', dest='verbosity', default='1', + type='choice', choices=['0', '1', '2'], + help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'), + ) + help = "Runs migrations for all apps." + args = "[appname] [migrationname|zero] [--all] [--list] [--skip] [--merge] [--no-initial-data] [--fake] [--db-dry-run] [--database=dbalias]" + + def handle(self, app=None, target=None, skip=False, merge=False, backwards=False, fake=False, db_dry_run=False, show_list=False, show_changes=False, database=DEFAULT_DB_ALIAS, delete_ghosts=False, ignore_ghosts=False, **options): + + # NOTE: THIS IS DUPLICATED FROM django.core.management.commands.syncdb + # This code imports any module named 'management' in INSTALLED_APPS. + # The 'management' module is the preferred way of listening to post_syncdb + # signals, and since we're sending those out with create_table migrations, + # we need apps to behave correctly. + for app_name in settings.INSTALLED_APPS: + try: + import_module('.management', app_name) + except ImportError as exc: + msg = exc.args[0] + if not msg.startswith('No module named') or 'management' not in msg: + raise + # END DJANGO DUPE CODE + + # if all_apps flag is set, shift app over to target + if options.get('all_apps', False): + target = app + app = None + + # Migrate each app + if app: + try: + apps = [Migrations(app)] + except NoMigrations: + print("The app '%s' does not appear to use migrations." % app) + print("./manage.py migrate " + self.args) + return + else: + apps = list(migration.all_migrations()) + + # Do we need to show the list of migrations? + if show_list and apps: + list_migrations(apps, database, **options) + + if show_changes and apps: + show_migration_changes(apps) + + if not (show_list or show_changes): + + for app in apps: + result = migration.migrate_app( + app, + target_name = target, + fake = fake, + db_dry_run = db_dry_run, + verbosity = int(options.get('verbosity', 0)), + interactive = options.get('interactive', True), + load_initial_data = not options.get('no_initial_data', False), + merge = merge, + skip = skip, + database = database, + delete_ghosts = delete_ghosts, + ignore_ghosts = ignore_ghosts, + ) + if result is False: + sys.exit(1) # Migration failed, so the command fails. + + +def list_migrations(apps, database = DEFAULT_DB_ALIAS, **options): + """ + Prints a list of all available migrations, and which ones are currently applied. + Accepts a list of Migrations instances. + """ + from south.models import MigrationHistory + applied_migrations = MigrationHistory.objects.filter(app_name__in=[app.app_label() for app in apps]) + if database != DEFAULT_DB_ALIAS: + applied_migrations = applied_migrations.using(database) + applied_migrations_lookup = dict(('%s.%s' % (mi.app_name, mi.migration), mi) for mi in applied_migrations) + + print() + for app in apps: + print(" " + app.app_label()) + # Get the migrations object + for migration in app: + full_name = migration.app_label() + "." + migration.name() + if full_name in applied_migrations_lookup: + applied_migration = applied_migrations_lookup[full_name] + print(format_migration_list_item(migration.name(), applied=applied_migration.applied, **options)) + else: + print(format_migration_list_item(migration.name(), applied=False, **options)) + print() + +def show_migration_changes(apps): + """ + Prints a list of all available migrations, and which ones are currently applied. + Accepts a list of Migrations instances. + + Much simpler, less clear, and much less robust version: + grep "ing " migrations/*.py + """ + for app in apps: + print(app.app_label()) + # Get the migrations objects + migrations = [migration for migration in app] + # we use reduce to compare models in pairs, not to generate a value + reduce(diff_migrations, migrations) + +def format_migration_list_item(name, applied=True, **options): + if applied: + if int(options.get('verbosity')) >= 2: + return ' (*) %-80s (applied %s)' % (name, applied) + else: + return ' (*) %s' % name + else: + return ' ( ) %s' % name + +def diff_migrations(migration1, migration2): + + def model_name(models, model): + return models[model].get('Meta', {}).get('object_name', model) + + def field_name(models, model, field): + return '%s.%s' % (model_name(models, model), field) + + print(" " + migration2.name()) + + models1 = migration1.migration_class().models + models2 = migration2.migration_class().models + + # find new models + for model in models2.keys(): + if not model in models1.keys(): + print(' added model %s' % model_name(models2, model)) + + # find removed models + for model in models1.keys(): + if not model in models2.keys(): + print(' removed model %s' % model_name(models1, model)) + + # compare models + for model in models1: + if model in models2: + + # find added fields + for field in models2[model]: + if not field in models1[model]: + print(' added field %s' % field_name(models2, model, field)) + + # find removed fields + for field in models1[model]: + if not field in models2[model]: + print(' removed field %s' % field_name(models1, model, field)) + + # compare fields + for field in models1[model]: + if field in models2[model]: + + name = field_name(models1, model, field) + + # compare field attributes + field_value1 = models1[model][field] + field_value2 = models2[model][field] + + # if a field has become a class, or vice versa + if type(field_value1) != type(field_value2): + print(' type of %s changed from %s to %s' % ( + name, field_value1, field_value2)) + + # if class + elif isinstance(field_value1, dict): + # print ' %s is a class' % name + pass + + # else regular field + else: + + type1, attr_list1, field_attrs1 = models1[model][field] + type2, attr_list2, field_attrs2 = models2[model][field] + + if type1 != type2: + print(' %s type changed from %s to %s' % ( + name, type1, type2)) + + if attr_list1 != []: + print(' %s list %s is not []' % ( + name, attr_list1)) + if attr_list2 != []: + print(' %s list %s is not []' % ( + name, attr_list2)) + if attr_list1 != attr_list2: + print(' %s list changed from %s to %s' % ( + name, attr_list1, attr_list2)) + + # find added field attributes + for attr in field_attrs2: + if not attr in field_attrs1: + print(' added %s attribute %s=%s' % ( + name, attr, field_attrs2[attr])) + + # find removed field attributes + for attr in field_attrs1: + if not attr in field_attrs2: + print(' removed attribute %s(%s=%s)' % ( + name, attr, field_attrs1[attr])) + + # compare field attributes + for attr in field_attrs1: + if attr in field_attrs2: + + value1 = field_attrs1[attr] + value2 = field_attrs2[attr] + if value1 != value2: + print(' %s attribute %s changed from %s to %s' % ( + name, attr, value1, value2)) + + return migration2 diff --git a/lib/python2.7/site-packages/south/management/commands/migrationcheck.py b/lib/python2.7/site-packages/south/management/commands/migrationcheck.py new file mode 100644 index 0000000..f498d0b --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/migrationcheck.py @@ -0,0 +1,67 @@ +from django.core.exceptions import ImproperlyConfigured +from django.core.management import call_command, CommandError +from django.core.management.base import BaseCommand +from django.conf import settings +from django.db.models import loading +from django.test import simple + +from south.migration import Migrations +from south.exceptions import NoMigrations +from south.hacks import hacks + +class Command(BaseCommand): + help = "Runs migrations for each app in turn, detecting missing depends_on values." + usage_str = "Usage: ./manage.py migrationcheck" + + def handle(self, check_app_name=None, **options): + runner = simple.DjangoTestSuiteRunner(verbosity=0) + err_msg = "Failed to migrate %s; see output for hints at missing dependencies:\n" + hacks.patch_flush_during_test_db_creation() + failures = 0 + if check_app_name is None: + app_names = settings.INSTALLED_APPS + else: + app_names = [check_app_name] + for app_name in app_names: + app_label = app_name.split(".")[-1] + if app_name == 'south': + continue + + try: + Migrations(app_name) + except (NoMigrations, ImproperlyConfigured): + continue + app = loading.get_app(app_label) + + verbosity = int(options.get('verbosity', 1)) + if verbosity >= 1: + self.stderr.write("processing %s\n" % app_name) + + old_config = runner.setup_databases() + try: + call_command('migrate', app_label, noinput=True, verbosity=verbosity) + for model in loading.get_models(app): + dummy = model._default_manager.exists() + except (KeyboardInterrupt, SystemExit): + raise + except Exception as e: + failures += 1 + if verbosity >= 1: + self.stderr.write(err_msg % app_name) + self.stderr.write("%s\n" % e) + finally: + runner.teardown_databases(old_config) + if failures > 0: + raise CommandError("Missing depends_on found in %s app(s)." % failures) + self.stderr.write("No missing depends_on found.\n") +# +#for each app: +# start with blank db. +# syncdb only south (and contrib?) +# +# migrate a single app all the way up. any errors is missing depends_on. +# for all models of that app, try the default manager: +# from django.db.models import loading +# for m in loading.get_models(loading.get_app('a')): +# m._default_manager.exists() +# Any error is also a missing depends on. diff --git a/lib/python2.7/site-packages/south/management/commands/schemamigration.py b/lib/python2.7/site-packages/south/management/commands/schemamigration.py new file mode 100644 index 0000000..efd4266 --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/schemamigration.py @@ -0,0 +1,229 @@ +""" +Startmigration command, version 2. +""" + +from __future__ import print_function + +import sys +import os +import re +import string +import random +import inspect +from optparse import make_option + +try: + set +except NameError: + from sets import Set as set + +from django.core.management.base import BaseCommand +from django.core.management.color import no_style +from django.core.exceptions import ImproperlyConfigured +from django.db import models +from django.conf import settings + +from south.migration import Migrations, migrate_app +from south.models import MigrationHistory +from south.exceptions import NoMigrations +from south.creator import changes, actions, freezer +from south.management.commands.datamigration import Command as DataCommand + +class Command(DataCommand): + option_list = DataCommand.option_list + ( + make_option('--add-model', action='append', dest='added_model_list', type='string', + help='Generate a Create Table migration for the specified model. Add multiple models to this migration with subsequent --add-model parameters.'), + make_option('--add-field', action='append', dest='added_field_list', type='string', + help='Generate an Add Column migration for the specified modelname.fieldname - you can use this multiple times to add more than one column.'), + make_option('--add-index', action='append', dest='added_index_list', type='string', + help='Generate an Add Index migration for the specified modelname.fieldname - you can use this multiple times to add more than one column.'), + make_option('--initial', action='store_true', dest='initial', default=False, + help='Generate the initial schema for the app.'), + make_option('--auto', action='store_true', dest='auto', default=False, + help='Attempt to automatically detect differences from the last migration.'), + make_option('--empty', action='store_true', dest='empty', default=False, + help='Make a blank migration.'), + make_option('--update', action='store_true', dest='update', default=False, + help='Update the most recent migration instead of creating a new one. Rollback this migration if it is already applied.'), + ) + help = "Creates a new template schema migration for the given app" + usage_str = "Usage: ./manage.py schemamigration appname migrationname [--empty] [--initial] [--auto] [--add-model ModelName] [--add-field ModelName.field_name] [--stdout]" + + def handle(self, app=None, name="", added_model_list=None, added_field_list=None, freeze_list=None, initial=False, auto=False, stdout=False, added_index_list=None, verbosity=1, empty=False, update=False, **options): + + # Any supposed lists that are None become empty lists + added_model_list = added_model_list or [] + added_field_list = added_field_list or [] + added_index_list = added_index_list or [] + freeze_list = freeze_list or [] + + # --stdout means name = - + if stdout: + name = "-" + + # Only allow valid names + if re.search('[^_\w]', name) and name != "-": + self.error("Migration names should contain only alphanumeric characters and underscores.") + + # Make sure options are compatable + if initial and (added_model_list or added_field_list or auto): + self.error("You cannot use --initial and other options together\n" + self.usage_str) + + if auto and (added_model_list or added_field_list or initial): + self.error("You cannot use --auto and other options together\n" + self.usage_str) + + if not app: + self.error("You must provide an app to create a migration for.\n" + self.usage_str) + + # See if the app exists + app = app.split(".")[-1] + try: + app_module = models.get_app(app) + except ImproperlyConfigured: + print("There is no enabled application matching '%s'." % app) + return + + # Get the Migrations for this app (creating the migrations dir if needed) + migrations = Migrations(app, force_creation=True, verbose_creation=int(verbosity) > 0) + + # What actions do we need to do? + if auto: + # Get the old migration + try: + last_migration = migrations[-2 if update else -1] + except IndexError: + self.error("You cannot use --auto on an app with no migrations. Try --initial.") + # Make sure it has stored models + if migrations.app_label() not in getattr(last_migration.migration_class(), "complete_apps", []): + self.error("You cannot use automatic detection, since the previous migration does not have this whole app frozen.\nEither make migrations using '--freeze %s' or set 'SOUTH_AUTO_FREEZE_APP = True' in your settings.py." % migrations.app_label()) + # Alright, construct two model dicts to run the differ on. + old_defs = dict( + (k, v) for k, v in last_migration.migration_class().models.items() + if k.split(".")[0] == migrations.app_label() + ) + new_defs = dict( + (k, v) for k, v in freezer.freeze_apps([migrations.app_label()]).items() + if k.split(".")[0] == migrations.app_label() + ) + change_source = changes.AutoChanges( + migrations = migrations, + old_defs = old_defs, + old_orm = last_migration.orm(), + new_defs = new_defs, + ) + + elif initial: + # Do an initial migration + change_source = changes.InitialChanges(migrations) + + else: + # Read the commands manually off of the arguments + if (added_model_list or added_field_list or added_index_list): + change_source = changes.ManualChanges( + migrations, + added_model_list, + added_field_list, + added_index_list, + ) + elif empty: + change_source = None + else: + print("You have not passed any of --initial, --auto, --empty, --add-model, --add-field or --add-index.", file=sys.stderr) + sys.exit(1) + + # Validate this so we can access the last migration without worrying + if update and not migrations: + self.error("You cannot use --update on an app with no migrations.") + + # if not name, there's an error + if not name: + if change_source: + name = change_source.suggest_name() + if update: + name = re.sub(r'^\d{4}_', '', migrations[-1].name()) + if not name: + self.error("You must provide a name for this migration\n" + self.usage_str) + + # Get the actions, and then insert them into the actions lists + forwards_actions = [] + backwards_actions = [] + if change_source: + for action_name, params in change_source.get_changes(): + # Run the correct Action class + try: + action_class = getattr(actions, action_name) + except AttributeError: + raise ValueError("Invalid action name from source: %s" % action_name) + else: + action = action_class(**params) + action.add_forwards(forwards_actions) + action.add_backwards(backwards_actions) + print(action.console_line(), file=sys.stderr) + + # Nowt happen? That's not good for --auto. + if auto and not forwards_actions: + self.error("Nothing seems to have changed.") + + # Work out which apps to freeze + apps_to_freeze = self.calc_frozen_apps(migrations, freeze_list) + + # So, what's in this file, then? + file_contents = self.get_migration_template() % { + "forwards": "\n".join(forwards_actions or [" pass"]), + "backwards": "\n".join(backwards_actions or [" pass"]), + "frozen_models": freezer.freeze_apps_to_string(apps_to_freeze), + "complete_apps": apps_to_freeze and "complete_apps = [%s]" % (", ".join(map(repr, apps_to_freeze))) or "" + } + + # Deal with update mode as late as possible, avoid a rollback as long + # as something else can go wrong. + if update: + last_migration = migrations[-1] + if MigrationHistory.objects.filter(applied__isnull=False, app_name=app, migration=last_migration.name()): + print("Migration to be updated, %s, is already applied, rolling it back now..." % last_migration.name(), file=sys.stderr) + migrate_app(migrations, 'current-1', verbosity=verbosity) + for ext in ('py', 'pyc'): + old_filename = "%s.%s" % (os.path.join(migrations.migrations_dir(), last_migration.filename), ext) + if os.path.isfile(old_filename): + os.unlink(old_filename) + migrations.remove(last_migration) + + # See what filename is next in line. We assume they use numbers. + new_filename = migrations.next_filename(name) + + # - is a special name which means 'print to stdout' + if name == "-": + print(file_contents) + # Write the migration file if the name isn't - + else: + fp = open(os.path.join(migrations.migrations_dir(), new_filename), "w") + fp.write(file_contents) + fp.close() + verb = 'Updated' if update else 'Created' + if empty: + print("%s %s. You must now edit this migration and add the code for each direction." % (verb, new_filename), file=sys.stderr) + else: + print("%s %s. You can now apply this migration with: ./manage.py migrate %s" % (verb, new_filename, app), file=sys.stderr) + + def get_migration_template(self): + return MIGRATION_TEMPLATE + + +MIGRATION_TEMPLATE = """# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): +%(forwards)s + + def backwards(self, orm): +%(backwards)s + + models = %(frozen_models)s + + %(complete_apps)s""" diff --git a/lib/python2.7/site-packages/south/management/commands/startmigration.py b/lib/python2.7/site-packages/south/management/commands/startmigration.py new file mode 100644 index 0000000..e4fcf45 --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/startmigration.py @@ -0,0 +1,33 @@ +""" +Now-obsolete startmigration command. +""" + +from __future__ import print_function + +from optparse import make_option + +from django.core.management.base import BaseCommand +from django.core.management.color import no_style + +class Command(BaseCommand): + option_list = BaseCommand.option_list + ( + make_option('--model', action='append', dest='added_model_list', type='string', + help='Generate a Create Table migration for the specified model. Add multiple models to this migration with subsequent --add-model parameters.'), + make_option('--add-field', action='append', dest='added_field_list', type='string', + help='Generate an Add Column migration for the specified modelname.fieldname - you can use this multiple times to add more than one column.'), + make_option('--add-index', action='append', dest='added_index_list', type='string', + help='Generate an Add Index migration for the specified modelname.fieldname - you can use this multiple times to add more than one column.'), + make_option('--initial', action='store_true', dest='initial', default=False, + help='Generate the initial schema for the app.'), + make_option('--auto', action='store_true', dest='auto', default=False, + help='Attempt to automatically detect differences from the last migration.'), + make_option('--freeze', action='append', dest='freeze_list', type='string', + help='Freeze the specified model(s). Pass in either an app name (to freeze the whole app) or a single model, as appname.modelname.'), + make_option('--stdout', action='store_true', dest='stdout', default=False, + help='Print the migration to stdout instead of writing it to a file.'), + ) + help = "Deprecated command" + + def handle(self, app=None, name="", added_model_list=None, added_field_list=None, initial=False, freeze_list=None, auto=False, stdout=False, added_index_list=None, **options): + + print("The 'startmigration' command is now deprecated; please use the new 'schemamigration' and 'datamigration' commands.") diff --git a/lib/python2.7/site-packages/south/management/commands/syncdb.py b/lib/python2.7/site-packages/south/management/commands/syncdb.py new file mode 100644 index 0000000..17fc22c --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/syncdb.py @@ -0,0 +1,115 @@ +""" +Overridden syncdb command +""" + +from __future__ import print_function + +import sys +from optparse import make_option + +from django.core.management.base import NoArgsCommand, BaseCommand +from django.core.management.color import no_style +from django.utils.datastructures import SortedDict +from django.core.management.commands import syncdb +from django.conf import settings +from django.db import models +from django.db.models.loading import cache +from django.core import management + +from south.db import dbs +from south import migration +from south.exceptions import NoMigrations + +def get_app_label(app): + return '.'.join( app.__name__.split('.')[0:-1] ) + +class Command(NoArgsCommand): + option_list = syncdb.Command.option_list + ( + make_option('--migrate', action='store_true', dest='migrate', default=False, + help='Tells South to also perform migrations after the sync. Default for during testing, and other internal calls.'), + make_option('--all', action='store_true', dest='migrate_all', default=False, + help='Makes syncdb work on all apps, even migrated ones. Be careful!'), + ) + if '--verbosity' not in [opt.get_opt_string() for opt in syncdb.Command.option_list]: + option_list += ( + make_option('--verbosity', action='store', dest='verbosity', default='1', + type='choice', choices=['0', '1', '2'], + help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'), + ) + help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created, except those which use migrations." + + def handle_noargs(self, migrate_all=False, **options): + + # Import the 'management' module within each installed app, to register + # dispatcher events. + # This is copied from Django, to fix bug #511. + try: + from django.utils.importlib import import_module + except ImportError: + pass # TODO: Remove, only for Django1.0 + else: + for app_name in settings.INSTALLED_APPS: + try: + import_module('.management', app_name) + except ImportError as exc: + msg = exc.args[0] + if not msg.startswith('No module named') or 'management' not in msg: + raise + + # Work out what uses migrations and so doesn't need syncing + apps_needing_sync = [] + apps_migrated = [] + for app in models.get_apps(): + app_label = get_app_label(app) + if migrate_all: + apps_needing_sync.append(app_label) + else: + try: + migrations = migration.Migrations(app_label) + except NoMigrations: + # It needs syncing + apps_needing_sync.append(app_label) + else: + # This is a migrated app, leave it + apps_migrated.append(app_label) + verbosity = int(options.get('verbosity', 0)) + + # Run syncdb on only the ones needed + if verbosity: + print("Syncing...") + + old_installed, settings.INSTALLED_APPS = settings.INSTALLED_APPS, apps_needing_sync + old_app_store, cache.app_store = cache.app_store, SortedDict([ + (k, v) for (k, v) in cache.app_store.items() + if get_app_label(k) in apps_needing_sync + ]) + + # This will allow the setting of the MySQL storage engine, for example. + for db in dbs.values(): + db.connection_init() + + # OK, run the actual syncdb + syncdb.Command().execute(**options) + + settings.INSTALLED_APPS = old_installed + cache.app_store = old_app_store + + # Migrate if needed + if options.get('migrate', True): + if verbosity: + print("Migrating...") + # convert from store_true to store_false + options['no_initial_data'] = not options.get('load_initial_data', True) + management.call_command('migrate', **options) + + # Be obvious about what we did + if verbosity: + print("\nSynced:\n > %s" % "\n > ".join(apps_needing_sync)) + + if options.get('migrate', True): + if verbosity: + print("\nMigrated:\n - %s" % "\n - ".join(apps_migrated)) + else: + if verbosity: + print("\nNot synced (use migrations):\n - %s" % "\n - ".join(apps_migrated)) + print("(use ./manage.py migrate to migrate these)") diff --git a/lib/python2.7/site-packages/south/management/commands/test.py b/lib/python2.7/site-packages/south/management/commands/test.py new file mode 100644 index 0000000..9901786 --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/test.py @@ -0,0 +1,8 @@ +from django.core.management.commands import test + +from south.management.commands import patch_for_test_db_setup + +class Command(test.Command): + def handle(self, *args, **kwargs): + patch_for_test_db_setup() + super(Command, self).handle(*args, **kwargs) diff --git a/lib/python2.7/site-packages/south/management/commands/testserver.py b/lib/python2.7/site-packages/south/management/commands/testserver.py new file mode 100644 index 0000000..3c3c4b5 --- /dev/null +++ b/lib/python2.7/site-packages/south/management/commands/testserver.py @@ -0,0 +1,8 @@ +from django.core.management.commands import testserver + +from south.management.commands import patch_for_test_db_setup + +class Command(testserver.Command): + def handle(self, *args, **kwargs): + patch_for_test_db_setup() + super(Command, self).handle(*args, **kwargs) |