diff options
Diffstat (limited to 'lib/python2.7/site-packages/south/creator')
-rw-r--r-- | lib/python2.7/site-packages/south/creator/__init__.py | 5 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/creator/actions.py | 559 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/creator/changes.py | 506 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/creator/freezer.py | 192 |
4 files changed, 0 insertions, 1262 deletions
diff --git a/lib/python2.7/site-packages/south/creator/__init__.py b/lib/python2.7/site-packages/south/creator/__init__.py deleted file mode 100644 index 96a1a80..0000000 --- a/lib/python2.7/site-packages/south/creator/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -""" -The creator module is responsible for making new migration files, either -as blank templates or autodetecting changes. It contains code that used to -all be in startmigration.py. -""" diff --git a/lib/python2.7/site-packages/south/creator/actions.py b/lib/python2.7/site-packages/south/creator/actions.py deleted file mode 100644 index 2ffc8ca..0000000 --- a/lib/python2.7/site-packages/south/creator/actions.py +++ /dev/null @@ -1,559 +0,0 @@ -""" -Actions - things like 'a model was removed' or 'a field was changed'. -Each one has a class, which can take the action description and insert code -blocks into the forwards() and backwards() methods, in the right place. -""" - -from __future__ import print_function - -import sys - -from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT -from django.db.models.fields import FieldDoesNotExist, NOT_PROVIDED, CharField, TextField - -from south.modelsinspector import value_clean -from south.creator.freezer import remove_useless_attributes, model_key -from south.utils import datetime_utils -from south.utils.py3 import raw_input - - -class Action(object): - """ - Generic base Action class. Contains utility methods for inserting into - the forwards() and backwards() method lists. - """ - - prepend_forwards = False - prepend_backwards = False - - def forwards_code(self): - raise NotImplementedError - - def backwards_code(self): - raise NotImplementedError - - def add_forwards(self, forwards): - if self.prepend_forwards: - forwards.insert(0, self.forwards_code()) - else: - forwards.append(self.forwards_code()) - - def add_backwards(self, backwards): - if self.prepend_backwards: - backwards.insert(0, self.backwards_code()) - else: - backwards.append(self.backwards_code()) - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - raise NotImplementedError - - @classmethod - def triples_to_defs(cls, fields): - # Turn the (class, args, kwargs) format into a string - for field, triple in fields.items(): - fields[field] = cls.triple_to_def(triple) - return fields - - @classmethod - def triple_to_def(cls, triple): - "Turns a single triple into a definition." - return "self.gf(%r)(%s)" % ( - triple[0], # Field full path - ", ".join(triple[1] + ["%s=%s" % (kwd, val) for kwd, val in triple[2].items()]), # args and kwds - ) - - -class AddModel(Action): - """ - Addition of a model. Takes the Model subclass that is being created. - """ - - FORWARDS_TEMPLATE = ''' - # Adding model '%(model_name)s' - db.create_table(%(table_name)r, ( - %(field_defs)s - )) - db.send_create_signal(%(app_label)r, [%(model_name)r])'''[1:] + "\n" - - BACKWARDS_TEMPLATE = ''' - # Deleting model '%(model_name)s' - db.delete_table(%(table_name)r)'''[1:] + "\n" - - def __init__(self, model, model_def): - self.model = model - self.model_def = model_def - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " + Added model %s.%s" % ( - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def forwards_code(self): - "Produces the code snippet that gets put into forwards()" - field_defs = ",\n ".join([ - "(%r, %s)" % (name, defn) for name, defn - in self.triples_to_defs(self.model_def).items() - ]) + "," - - return self.FORWARDS_TEMPLATE % { - "model_name": self.model._meta.object_name, - "table_name": self.model._meta.db_table, - "app_label": self.model._meta.app_label, - "field_defs": field_defs, - } - - def backwards_code(self): - "Produces the code snippet that gets put into backwards()" - return self.BACKWARDS_TEMPLATE % { - "model_name": self.model._meta.object_name, - "table_name": self.model._meta.db_table, - } - - -class DeleteModel(AddModel): - """ - Deletion of a model. Takes the Model subclass that is being created. - """ - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " - Deleted model %s.%s" % ( - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def forwards_code(self): - return AddModel.backwards_code(self) - - def backwards_code(self): - return AddModel.forwards_code(self) - - -class _NullIssuesField(object): - """ - A field that might need to ask a question about rogue NULL values. - """ - - issue_with_backward_migration = False - irreversible = False - - IRREVERSIBLE_TEMPLATE = ''' - # User chose to not deal with backwards NULL issues for '%(model_name)s.%(field_name)s' - raise RuntimeError("Cannot reverse this migration. '%(model_name)s.%(field_name)s' and its values cannot be restored.") - - # The following code is provided here to aid in writing a correct migration''' - - def deal_with_not_null_no_default(self, field, field_def): - # If it's a CharField or TextField that's blank, skip this step. - if isinstance(field, (CharField, TextField)) and field.blank: - field_def[2]['default'] = repr("") - return - # Oh dear. Ask them what to do. - print(" ? The field '%s.%s' does not have a default specified, yet is NOT NULL." % ( - self.model._meta.object_name, - field.name, - )) - print(" ? Since you are %s, you MUST specify a default" % self.null_reason) - print(" ? value to use for existing rows. Would you like to:") - print(" ? 1. Quit now"+("." if self.issue_with_backward_migration else ", and add a default to the field in models.py" )) - print(" ? 2. Specify a one-off value to use for existing columns now") - if self.issue_with_backward_migration: - print(" ? 3. Disable the backwards migration by raising an exception; you can edit the migration to fix it later") - while True: - choice = raw_input(" ? Please select a choice: ") - if choice == "1": - sys.exit(1) - elif choice == "2": - break - elif choice == "3" and self.issue_with_backward_migration: - break - else: - print(" ! Invalid choice.") - if choice == "2": - self.add_one_time_default(field, field_def) - elif choice == "3": - self.irreversible = True - - def add_one_time_default(self, field, field_def): - # OK, they want to pick their own one-time default. Who are we to refuse? - print(" ? Please enter Python code for your one-off default value.") - print(" ? The datetime module is available, so you can do e.g. datetime.date.today()") - while True: - code = raw_input(" >>> ") - if not code: - print(" ! Please enter some code, or 'exit' (with no quotes) to exit.") - elif code == "exit": - sys.exit(1) - else: - try: - result = eval(code, {}, {"datetime": datetime_utils}) - except (SyntaxError, NameError) as e: - print(" ! Invalid input: %s" % e) - else: - break - # Right, add the default in. - field_def[2]['default'] = value_clean(result) - - def irreversable_code(self, field): - return self.IRREVERSIBLE_TEMPLATE % { - "model_name": self.model._meta.object_name, - "table_name": self.model._meta.db_table, - "field_name": field.name, - "field_column": field.column, - } - - -class AddField(Action, _NullIssuesField): - """ - Adds a field to a model. Takes a Model class and the field name. - """ - - null_reason = "adding this field" - - FORWARDS_TEMPLATE = ''' - # Adding field '%(model_name)s.%(field_name)s' - db.add_column(%(table_name)r, %(field_name)r, - %(field_def)s, - keep_default=False)'''[1:] + "\n" - - BACKWARDS_TEMPLATE = ''' - # Deleting field '%(model_name)s.%(field_name)s' - db.delete_column(%(table_name)r, %(field_column)r)'''[1:] + "\n" - - def __init__(self, model, field, field_def): - self.model = model - self.field = field - self.field_def = field_def - - # See if they've made a NOT NULL column but also have no default (far too common) - is_null = self.field.null - default = (self.field.default is not None) and (self.field.default is not NOT_PROVIDED) - - if not is_null and not default: - self.deal_with_not_null_no_default(self.field, self.field_def) - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " + Added field %s on %s.%s" % ( - self.field.name, - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def forwards_code(self): - - return self.FORWARDS_TEMPLATE % { - "model_name": self.model._meta.object_name, - "table_name": self.model._meta.db_table, - "field_name": self.field.name, - "field_column": self.field.column, - "field_def": self.triple_to_def(self.field_def), - } - - def backwards_code(self): - return self.BACKWARDS_TEMPLATE % { - "model_name": self.model._meta.object_name, - "table_name": self.model._meta.db_table, - "field_name": self.field.name, - "field_column": self.field.column, - } - - -class DeleteField(AddField): - """ - Removes a field from a model. Takes a Model class and the field name. - """ - - null_reason = "removing this field" - issue_with_backward_migration = True - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " - Deleted field %s on %s.%s" % ( - self.field.name, - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def forwards_code(self): - return AddField.backwards_code(self) - - def backwards_code(self): - if not self.irreversible: - return AddField.forwards_code(self) - else: - return self.irreversable_code(self.field) + AddField.forwards_code(self) - - -class ChangeField(Action, _NullIssuesField): - """ - Changes a field's type/options on a model. - """ - - null_reason = "making this field non-nullable" - - FORWARDS_TEMPLATE = BACKWARDS_TEMPLATE = ''' - # Changing field '%(model_name)s.%(field_name)s' - db.alter_column(%(table_name)r, %(field_column)r, %(field_def)s)''' - - RENAME_TEMPLATE = ''' - # Renaming column for '%(model_name)s.%(field_name)s' to match new field type. - db.rename_column(%(table_name)r, %(old_column)r, %(new_column)r)''' - - def __init__(self, model, old_field, new_field, old_def, new_def): - self.model = model - self.old_field = old_field - self.new_field = new_field - self.old_def = old_def - self.new_def = new_def - - # See if they've changed a not-null field to be null - new_default = (self.new_field.default is not None) and (self.new_field.default is not NOT_PROVIDED) - old_default = (self.old_field.default is not None) and (self.old_field.default is not NOT_PROVIDED) - if self.old_field.null and not self.new_field.null and not new_default: - self.deal_with_not_null_no_default(self.new_field, self.new_def) - if not self.old_field.null and self.new_field.null and not old_default: - self.null_reason = "making this field nullable" - self.issue_with_backward_migration = True - self.deal_with_not_null_no_default(self.old_field, self.old_def) - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " ~ Changed field %s on %s.%s" % ( - self.new_field.name, - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def _code(self, old_field, new_field, new_def): - - output = "" - - if self.old_field.column != self.new_field.column: - output += self.RENAME_TEMPLATE % { - "model_name": self.model._meta.object_name, - "table_name": self.model._meta.db_table, - "field_name": new_field.name, - "old_column": old_field.column, - "new_column": new_field.column, - } - - output += self.FORWARDS_TEMPLATE % { - "model_name": self.model._meta.object_name, - "table_name": self.model._meta.db_table, - "field_name": new_field.name, - "field_column": new_field.column, - "field_def": self.triple_to_def(new_def), - } - - return output - - def forwards_code(self): - return self._code(self.old_field, self.new_field, self.new_def) - - def backwards_code(self): - change_code = self._code(self.new_field, self.old_field, self.old_def) - if not self.irreversible: - return change_code - else: - return self.irreversable_code(self.old_field) + change_code - - -class AddUnique(Action): - """ - Adds a unique constraint to a model. Takes a Model class and the field names. - """ - - FORWARDS_TEMPLATE = ''' - # Adding unique constraint on '%(model_name)s', fields %(field_names)s - db.create_unique(%(table_name)r, %(fields)r)'''[1:] + "\n" - - BACKWARDS_TEMPLATE = ''' - # Removing unique constraint on '%(model_name)s', fields %(field_names)s - db.delete_unique(%(table_name)r, %(fields)r)'''[1:] + "\n" - - prepend_backwards = True - - def __init__(self, model, fields): - self.model = model - self.fields = fields - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " + Added unique constraint for %s on %s.%s" % ( - [x.name for x in self.fields], - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def forwards_code(self): - - return self.FORWARDS_TEMPLATE % { - "model_name": self.model._meta.object_name, - "table_name": self.model._meta.db_table, - "fields": [field.column for field in self.fields], - "field_names": [field.name for field in self.fields], - } - - def backwards_code(self): - return self.BACKWARDS_TEMPLATE % { - "model_name": self.model._meta.object_name, - "table_name": self.model._meta.db_table, - "fields": [field.column for field in self.fields], - "field_names": [field.name for field in self.fields], - } - - -class DeleteUnique(AddUnique): - """ - Removes a unique constraint from a model. Takes a Model class and the field names. - """ - - prepend_forwards = True - prepend_backwards = False - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " - Deleted unique constraint for %s on %s.%s" % ( - [x.name for x in self.fields], - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def forwards_code(self): - return AddUnique.backwards_code(self) - - def backwards_code(self): - return AddUnique.forwards_code(self) - - -class AddIndex(AddUnique): - """ - Adds an index to a model field[s]. Takes a Model class and the field names. - """ - - FORWARDS_TEMPLATE = ''' - # Adding index on '%(model_name)s', fields %(field_names)s - db.create_index(%(table_name)r, %(fields)r)'''[1:] + "\n" - - BACKWARDS_TEMPLATE = ''' - # Removing index on '%(model_name)s', fields %(field_names)s - db.delete_index(%(table_name)r, %(fields)r)'''[1:] + "\n" - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " + Added index for %s on %s.%s" % ( - [x.name for x in self.fields], - self.model._meta.app_label, - self.model._meta.object_name, - ) - - -class DeleteIndex(AddIndex): - """ - Deletes an index off a model field[s]. Takes a Model class and the field names. - """ - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " + Deleted index for %s on %s.%s" % ( - [x.name for x in self.fields], - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def forwards_code(self): - return AddIndex.backwards_code(self) - - def backwards_code(self): - return AddIndex.forwards_code(self) - - -class AddM2M(Action): - """ - Adds a unique constraint to a model. Takes a Model class and the field names. - """ - - FORWARDS_TEMPLATE = ''' - # Adding M2M table for field %(field_name)s on '%(model_name)s' - m2m_table_name = %(table_name)s - db.create_table(m2m_table_name, ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - (%(left_field)r, models.ForeignKey(orm[%(left_model_key)r], null=False)), - (%(right_field)r, models.ForeignKey(orm[%(right_model_key)r], null=False)) - )) - db.create_unique(m2m_table_name, [%(left_column)r, %(right_column)r])'''[1:] + "\n" - - BACKWARDS_TEMPLATE = ''' - # Removing M2M table for field %(field_name)s on '%(model_name)s' - db.delete_table(%(table_name)s)'''[1:] + "\n" - - def __init__(self, model, field): - self.model = model - self.field = field - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " + Added M2M table for %s on %s.%s" % ( - self.field.name, - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def table_name(self): - # This is part of a workaround for the fact that Django uses - # different shortening for automatically generated m2m table names - # (as opposed to any explicitly specified table name) - f = self.field - explicit = f.db_table - if explicit: - return "%r" % explicit - else: - auto = "%s_%s" % (self.model._meta.db_table, f.name) - return 'db.shorten_name(%r)' % auto - - def forwards_code(self): - - return self.FORWARDS_TEMPLATE % { - "model_name": self.model._meta.object_name, - "field_name": self.field.name, - "table_name": self.table_name(), - "left_field": self.field.m2m_column_name()[:-3], # Remove the _id part - "left_column": self.field.m2m_column_name(), - "left_model_key": model_key(self.model), - "right_field": self.field.m2m_reverse_name()[:-3], # Remove the _id part - "right_column": self.field.m2m_reverse_name(), - "right_model_key": model_key(self.field.rel.to), - } - - def backwards_code(self): - - return self.BACKWARDS_TEMPLATE % { - "model_name": self.model._meta.object_name, - "field_name": self.field.name, - "table_name": self.table_name(), - } - - -class DeleteM2M(AddM2M): - """ - Adds a unique constraint to a model. Takes a Model class and the field names. - """ - - def console_line(self): - "Returns the string to print on the console, e.g. ' + Added field foo'" - return " - Deleted M2M table for %s on %s.%s" % ( - self.field.name, - self.model._meta.app_label, - self.model._meta.object_name, - ) - - def forwards_code(self): - return AddM2M.backwards_code(self) - - def backwards_code(self): - return AddM2M.forwards_code(self) - diff --git a/lib/python2.7/site-packages/south/creator/changes.py b/lib/python2.7/site-packages/south/creator/changes.py deleted file mode 100644 index 6cdbd19..0000000 --- a/lib/python2.7/site-packages/south/creator/changes.py +++ /dev/null @@ -1,506 +0,0 @@ -""" -Contains things to detect changes - either using options passed in on the -commandline, or by using autodetection, etc. -""" - -from __future__ import print_function - -from django.db import models -from django.contrib.contenttypes.generic import GenericRelation -from django.utils.datastructures import SortedDict - -from south.creator.freezer import remove_useless_attributes, freeze_apps, model_key -from south.utils import auto_through -from south.utils.py3 import string_types - -class BaseChanges(object): - """ - Base changes class. - """ - def suggest_name(self): - return '' - - def split_model_def(self, model, model_def): - """ - Given a model and its model def (a dict of field: triple), returns three - items: the real fields dict, the Meta dict, and the M2M fields dict. - """ - real_fields = SortedDict() - meta = SortedDict() - m2m_fields = SortedDict() - for name, triple in model_def.items(): - if name == "Meta": - meta = triple - elif isinstance(model._meta.get_field_by_name(name)[0], models.ManyToManyField): - m2m_fields[name] = triple - else: - real_fields[name] = triple - return real_fields, meta, m2m_fields - - def current_model_from_key(self, key): - app_label, model_name = key.split(".") - return models.get_model(app_label, model_name) - - def current_field_from_key(self, key, fieldname): - app_label, model_name = key.split(".") - # Special, for the magical field from order_with_respect_to - if fieldname == "_order": - field = models.IntegerField() - field.name = "_order" - field.attname = "_order" - field.column = "_order" - field.default = 0 - return field - # Otherwise, normal. - return models.get_model(app_label, model_name)._meta.get_field_by_name(fieldname)[0] - - -class AutoChanges(BaseChanges): - """ - Detects changes by 'diffing' two sets of frozen model definitions. - """ - - # Field types we don't generate add/remove field changes for. - IGNORED_FIELD_TYPES = [ - GenericRelation, - ] - - def __init__(self, migrations, old_defs, old_orm, new_defs): - self.migrations = migrations - self.old_defs = old_defs - self.old_orm = old_orm - self.new_defs = new_defs - - def suggest_name(self): - parts = ["auto"] - for change_name, params in self.get_changes(): - if change_name == "AddModel": - parts.append("add_%s" % params['model']._meta.object_name.lower()) - elif change_name == "DeleteModel": - parts.append("del_%s" % params['model']._meta.object_name.lower()) - elif change_name == "AddField": - parts.append("add_field_%s_%s" % ( - params['model']._meta.object_name.lower(), - params['field'].name, - )) - elif change_name == "DeleteField": - parts.append("del_field_%s_%s" % ( - params['model']._meta.object_name.lower(), - params['field'].name, - )) - elif change_name == "ChangeField": - parts.append("chg_field_%s_%s" % ( - params['model']._meta.object_name.lower(), - params['new_field'].name, - )) - elif change_name == "AddUnique": - parts.append("add_unique_%s_%s" % ( - params['model']._meta.object_name.lower(), - "_".join([x.name for x in params['fields']]), - )) - elif change_name == "DeleteUnique": - parts.append("del_unique_%s_%s" % ( - params['model']._meta.object_name.lower(), - "_".join([x.name for x in params['fields']]), - )) - elif change_name == "AddIndex": - parts.append("add_index_%s_%s" % ( - params['model']._meta.object_name.lower(), - "_".join([x.name for x in params['fields']]), - )) - elif change_name == "DeleteIndex": - parts.append("del_index_%s_%s" % ( - params['model']._meta.object_name.lower(), - "_".join([x.name for x in params['fields']]), - )) - return ("__".join(parts))[:70] - - def get_changes(self): - """ - Returns the difference between the old and new sets of models as a 5-tuple: - added_models, deleted_models, added_fields, deleted_fields, changed_fields - """ - - deleted_models = set() - - # See if anything's vanished - for key in self.old_defs: - if key not in self.new_defs: - # We shouldn't delete it if it was managed=False - old_fields, old_meta, old_m2ms = self.split_model_def(self.old_orm[key], self.old_defs[key]) - if old_meta.get("managed", "True") != "False": - # Alright, delete it. - yield ("DeleteModel", { - "model": self.old_orm[key], - "model_def": old_fields, - }) - # Also make sure we delete any M2Ms it had. - for fieldname in old_m2ms: - # Only delete its stuff if it wasn't a through=. - field = self.old_orm[key + ":" + fieldname] - if auto_through(field): - yield ("DeleteM2M", {"model": self.old_orm[key], "field": field}) - # And any index/uniqueness constraints it had - for attr, operation in (("unique_together", "DeleteUnique"), ("index_together", "DeleteIndex")): - together = eval(old_meta.get(attr, "[]")) - if together: - # If it's only a single tuple, make it into the longer one - if isinstance(together[0], string_types): - together = [together] - # For each combination, make an action for it - for fields in together: - yield (operation, { - "model": self.old_orm[key], - "fields": [self.old_orm[key]._meta.get_field_by_name(x)[0] for x in fields], - }) - # We always add it in here so we ignore it later - deleted_models.add(key) - - # Or appeared - for key in self.new_defs: - if key not in self.old_defs: - # We shouldn't add it if it's managed=False - new_fields, new_meta, new_m2ms = self.split_model_def(self.current_model_from_key(key), self.new_defs[key]) - if new_meta.get("managed", "True") != "False": - yield ("AddModel", { - "model": self.current_model_from_key(key), - "model_def": new_fields, - }) - # Also make sure we add any M2Ms it has. - for fieldname in new_m2ms: - # Only create its stuff if it wasn't a through=. - field = self.current_field_from_key(key, fieldname) - if auto_through(field): - yield ("AddM2M", {"model": self.current_model_from_key(key), "field": field}) - # And any index/uniqueness constraints it has - for attr, operation in (("unique_together", "AddUnique"), ("index_together", "AddIndex")): - together = eval(new_meta.get(attr, "[]")) - if together: - # If it's only a single tuple, make it into the longer one - if isinstance(together[0], string_types): - together = [together] - # For each combination, make an action for it - for fields in together: - yield (operation, { - "model": self.current_model_from_key(key), - "fields": [self.current_model_from_key(key)._meta.get_field_by_name(x)[0] for x in fields], - }) - - # Now, for every model that's stayed the same, check its fields. - for key in self.old_defs: - if key not in deleted_models: - - old_fields, old_meta, old_m2ms = self.split_model_def(self.old_orm[key], self.old_defs[key]) - new_fields, new_meta, new_m2ms = self.split_model_def(self.current_model_from_key(key), self.new_defs[key]) - - # Do nothing for models which are now not managed. - if new_meta.get("managed", "True") == "False": - continue - - # Find fields that have vanished. - for fieldname in old_fields: - if fieldname not in new_fields: - # Don't do it for any fields we're ignoring - field = self.old_orm[key + ":" + fieldname] - field_allowed = True - for field_type in self.IGNORED_FIELD_TYPES: - if isinstance(field, field_type): - field_allowed = False - if field_allowed: - # Looks alright. - yield ("DeleteField", { - "model": self.old_orm[key], - "field": field, - "field_def": old_fields[fieldname], - }) - - # And ones that have appeared - for fieldname in new_fields: - if fieldname not in old_fields: - # Don't do it for any fields we're ignoring - field = self.current_field_from_key(key, fieldname) - field_allowed = True - for field_type in self.IGNORED_FIELD_TYPES: - if isinstance(field, field_type): - field_allowed = False - if field_allowed: - # Looks alright. - yield ("AddField", { - "model": self.current_model_from_key(key), - "field": field, - "field_def": new_fields[fieldname], - }) - - # Find M2Ms that have vanished - for fieldname in old_m2ms: - if fieldname not in new_m2ms: - # Only delete its stuff if it wasn't a through=. - field = self.old_orm[key + ":" + fieldname] - if auto_through(field): - yield ("DeleteM2M", {"model": self.old_orm[key], "field": field}) - - # Find M2Ms that have appeared - for fieldname in new_m2ms: - if fieldname not in old_m2ms: - # Only create its stuff if it wasn't a through=. - field = self.current_field_from_key(key, fieldname) - if auto_through(field): - yield ("AddM2M", {"model": self.current_model_from_key(key), "field": field}) - - # For the ones that exist in both models, see if they were changed - for fieldname in set(old_fields).intersection(set(new_fields)): - # Non-index changes - if self.different_attributes( - remove_useless_attributes(old_fields[fieldname], True, True), - remove_useless_attributes(new_fields[fieldname], True, True)): - yield ("ChangeField", { - "model": self.current_model_from_key(key), - "old_field": self.old_orm[key + ":" + fieldname], - "new_field": self.current_field_from_key(key, fieldname), - "old_def": old_fields[fieldname], - "new_def": new_fields[fieldname], - }) - # Index changes - old_field = self.old_orm[key + ":" + fieldname] - new_field = self.current_field_from_key(key, fieldname) - if not old_field.db_index and new_field.db_index: - # They've added an index. - yield ("AddIndex", { - "model": self.current_model_from_key(key), - "fields": [new_field], - }) - if old_field.db_index and not new_field.db_index: - # They've removed an index. - yield ("DeleteIndex", { - "model": self.old_orm[key], - "fields": [old_field], - }) - # See if their uniques have changed - if old_field.unique != new_field.unique: - # Make sure we look at the one explicitly given to see what happened - if new_field.unique: - yield ("AddUnique", { - "model": self.current_model_from_key(key), - "fields": [new_field], - }) - else: - yield ("DeleteUnique", { - "model": self.old_orm[key], - "fields": [old_field], - }) - - # See if there's any M2Ms that have changed. - for fieldname in set(old_m2ms).intersection(set(new_m2ms)): - old_field = self.old_orm[key + ":" + fieldname] - new_field = self.current_field_from_key(key, fieldname) - # Have they _added_ a through= ? - if auto_through(old_field) and not auto_through(new_field): - yield ("DeleteM2M", {"model": self.old_orm[key], "field": old_field}) - # Have they _removed_ a through= ? - if not auto_through(old_field) and auto_through(new_field): - yield ("AddM2M", {"model": self.current_model_from_key(key), "field": new_field}) - - ## See if the {index,unique}_togethers have changed - for attr, add_operation, del_operation in (("unique_together", "AddUnique", "DeleteUnique"), ("index_together", "AddIndex", "DeleteIndex")): - # First, normalise them into lists of sets. - old_together = eval(old_meta.get(attr, "[]")) - new_together = eval(new_meta.get(attr, "[]")) - if old_together and isinstance(old_together[0], string_types): - old_together = [old_together] - if new_together and isinstance(new_together[0], string_types): - new_together = [new_together] - old_together = frozenset(tuple(o) for o in old_together) - new_together = frozenset(tuple(n) for n in new_together) - # See if any appeared or disappeared - disappeared = old_together.difference(new_together) - appeared = new_together.difference(old_together) - for item in disappeared: - yield (del_operation, { - "model": self.old_orm[key], - "fields": [self.old_orm[key + ":" + x] for x in item], - }) - for item in appeared: - yield (add_operation, { - "model": self.current_model_from_key(key), - "fields": [self.current_field_from_key(key, x) for x in item], - }) - - @classmethod - def is_triple(cls, triple): - "Returns whether the argument is a triple." - return isinstance(triple, (list, tuple)) and len(triple) == 3 and \ - isinstance(triple[0], string_types) and \ - isinstance(triple[1], (list, tuple)) and \ - isinstance(triple[2], dict) - - @classmethod - def different_attributes(cls, old, new): - """ - Backwards-compat comparison that ignores orm. on the RHS and not the left - and which knows django.db.models.fields.CharField = models.CharField. - Has a whole load of tests in tests/autodetection.py. - """ - - # If they're not triples, just do normal comparison - if not cls.is_triple(old) or not cls.is_triple(new): - return old != new - - # Expand them out into parts - old_field, old_pos, old_kwd = old - new_field, new_pos, new_kwd = new - - # Copy the positional and keyword arguments so we can compare them and pop off things - old_pos, new_pos = old_pos[:], new_pos[:] - old_kwd = dict(old_kwd.items()) - new_kwd = dict(new_kwd.items()) - - # Remove comparison of the existence of 'unique', that's done elsewhere. - # TODO: Make this work for custom fields where unique= means something else? - if "unique" in old_kwd: - del old_kwd['unique'] - if "unique" in new_kwd: - del new_kwd['unique'] - - # If the first bit is different, check it's not by dj.db.models... - if old_field != new_field: - if old_field.startswith("models.") and (new_field.startswith("django.db.models") \ - or new_field.startswith("django.contrib.gis")): - if old_field.split(".")[-1] != new_field.split(".")[-1]: - return True - else: - # Remove those fields from the final comparison - old_field = new_field = "" - - # If there's a positional argument in the first, and a 'to' in the second, - # see if they're actually comparable. - if (old_pos and "to" in new_kwd) and ("orm" in new_kwd['to'] and "orm" not in old_pos[0]): - # Do special comparison to fix #153 - try: - if old_pos[0] != new_kwd['to'].split("'")[1].split(".")[1]: - return True - except IndexError: - pass # Fall back to next comparison - # Remove those attrs from the final comparison - old_pos = old_pos[1:] - del new_kwd['to'] - - return old_field != new_field or old_pos != new_pos or old_kwd != new_kwd - - -class ManualChanges(BaseChanges): - """ - Detects changes by reading the command line. - """ - - def __init__(self, migrations, added_models, added_fields, added_indexes): - self.migrations = migrations - self.added_models = added_models - self.added_fields = added_fields - self.added_indexes = added_indexes - - def suggest_name(self): - bits = [] - for model_name in self.added_models: - bits.append('add_model_%s' % model_name) - for field_name in self.added_fields: - bits.append('add_field_%s' % field_name) - for index_name in self.added_indexes: - bits.append('add_index_%s' % index_name) - return '_'.join(bits).replace('.', '_') - - def get_changes(self): - # Get the model defs so we can use them for the yield later - model_defs = freeze_apps([self.migrations.app_label()]) - # Make the model changes - for model_name in self.added_models: - model = models.get_model(self.migrations.app_label(), model_name) - real_fields, meta, m2m_fields = self.split_model_def(model, model_defs[model_key(model)]) - yield ("AddModel", { - "model": model, - "model_def": real_fields, - }) - # And the field changes - for field_desc in self.added_fields: - try: - model_name, field_name = field_desc.split(".") - except (TypeError, ValueError): - raise ValueError("%r is not a valid field description." % field_desc) - model = models.get_model(self.migrations.app_label(), model_name) - real_fields, meta, m2m_fields = self.split_model_def(model, model_defs[model_key(model)]) - yield ("AddField", { - "model": model, - "field": model._meta.get_field_by_name(field_name)[0], - "field_def": real_fields[field_name], - }) - # And the indexes - for field_desc in self.added_indexes: - try: - model_name, field_name = field_desc.split(".") - except (TypeError, ValueError): - print("%r is not a valid field description." % field_desc) - model = models.get_model(self.migrations.app_label(), model_name) - yield ("AddIndex", { - "model": model, - "fields": [model._meta.get_field_by_name(field_name)[0]], - }) - - -class InitialChanges(BaseChanges): - """ - Creates all models; handles --initial. - """ - def suggest_name(self): - return 'initial' - - def __init__(self, migrations): - self.migrations = migrations - - def get_changes(self): - # Get the frozen models for this app - model_defs = freeze_apps([self.migrations.app_label()]) - - for model in models.get_models(models.get_app(self.migrations.app_label())): - - # Don't do anything for unmanaged, abstract or proxy models - if model._meta.abstract or getattr(model._meta, "proxy", False) or not getattr(model._meta, "managed", True): - continue - - real_fields, meta, m2m_fields = self.split_model_def(model, model_defs[model_key(model)]) - - # Firstly, add the main table and fields - yield ("AddModel", { - "model": model, - "model_def": real_fields, - }) - - # Then, add any indexing/uniqueness that's around - if meta: - for attr, operation in (("unique_together", "AddUnique"), ("index_together", "AddIndex")): - together = eval(meta.get(attr, "[]")) - if together: - # If it's only a single tuple, make it into the longer one - if isinstance(together[0], string_types): - together = [together] - # For each combination, make an action for it - for fields in together: - yield (operation, { - "model": model, - "fields": [model._meta.get_field_by_name(x)[0] for x in fields], - }) - - # Finally, see if there's some M2M action - for name, triple in m2m_fields.items(): - field = model._meta.get_field_by_name(name)[0] - # But only if it's not through=foo (#120) - if field.rel.through: - try: - # Django 1.1 and below - through_model = field.rel.through_model - except AttributeError: - # Django 1.2 - through_model = field.rel.through - if (not field.rel.through) or getattr(through_model._meta, "auto_created", False): - yield ("AddM2M", { - "model": model, - "field": field, - }) diff --git a/lib/python2.7/site-packages/south/creator/freezer.py b/lib/python2.7/site-packages/south/creator/freezer.py deleted file mode 100644 index 0f98cea..0000000 --- a/lib/python2.7/site-packages/south/creator/freezer.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -Handles freezing of models into FakeORMs. -""" - -from __future__ import print_function - -import sys - -from django.db import models -from django.db.models.base import ModelBase, Model -from django.contrib.contenttypes.generic import GenericRelation - -from south.utils import get_attribute, auto_through -from south import modelsinspector -from south.utils.py3 import string_types - -def freeze_apps(apps): - """ - Takes a list of app labels, and returns a string of their frozen form. - """ - if isinstance(apps, string_types): - apps = [apps] - frozen_models = set() - # For each app, add in all its models - for app in apps: - for model in models.get_models(models.get_app(app)): - # Only add if it's not abstract or proxy - if not model._meta.abstract and not getattr(model._meta, "proxy", False): - frozen_models.add(model) - # Now, add all the dependencies - for model in list(frozen_models): - frozen_models.update(model_dependencies(model)) - # Serialise! - model_defs = {} - model_classes = {} - for model in frozen_models: - model_defs[model_key(model)] = prep_for_freeze(model) - model_classes[model_key(model)] = model - # Check for any custom fields that failed to freeze. - missing_fields = False - for key, fields in model_defs.items(): - for field_name, value in fields.items(): - if value is None: - missing_fields = True - model_class = model_classes[key] - field_class = model_class._meta.get_field_by_name(field_name)[0] - print(" ! Cannot freeze field '%s.%s'" % (key, field_name)) - print(" ! (this field has class %s.%s)" % (field_class.__class__.__module__, field_class.__class__.__name__)) - if missing_fields: - print("") - print(" ! South cannot introspect some fields; this is probably because they are custom") - print(" ! fields. If they worked in 0.6 or below, this is because we have removed the") - print(" ! models parser (it often broke things).") - print(" ! To fix this, read http://south.aeracode.org/wiki/MyFieldsDontWork") - sys.exit(1) - - return model_defs - -def freeze_apps_to_string(apps): - return pprint_frozen_models(freeze_apps(apps)) - -### - -def model_key(model): - "For a given model, return 'appname.modelname'." - return "%s.%s" % (model._meta.app_label, model._meta.object_name.lower()) - -def prep_for_freeze(model): - """ - Takes a model and returns the ready-to-serialise dict (all you need - to do is just pretty-print it). - """ - fields = modelsinspector.get_model_fields(model, m2m=True) - # Remove useless attributes (like 'choices') - for name, field in fields.items(): - fields[name] = remove_useless_attributes(field) - # See if there's a Meta - fields['Meta'] = remove_useless_meta(modelsinspector.get_model_meta(model)) - # Add in our own special items to track the object name and managed - fields['Meta']['object_name'] = model._meta.object_name # Special: not eval'able. - if not getattr(model._meta, "managed", True): - fields['Meta']['managed'] = repr(model._meta.managed) - return fields - -### Dependency resolvers - -def model_dependencies(model, checked_models=None): - """ - Returns a set of models this one depends on to be defined; things like - OneToOneFields as ID, ForeignKeys everywhere, etc. - """ - depends = set() - checked_models = checked_models or set() - # Get deps for each field - for field in model._meta.fields + model._meta.many_to_many: - depends.update(field_dependencies(field, checked_models)) - # Add in any non-abstract bases - for base in model.__bases__: - if issubclass(base, models.Model) and hasattr(base, '_meta') and not base._meta.abstract: - depends.add(base) - # Now recurse - new_to_check = depends - checked_models - while new_to_check: - checked_model = new_to_check.pop() - if checked_model == model or checked_model in checked_models: - continue - checked_models.add(checked_model) - deps = model_dependencies(checked_model, checked_models) - # Loop through dependencies... - for dep in deps: - # If the new dep is not already checked, add to the queue - if (dep not in depends) and (dep not in new_to_check) and (dep not in checked_models): - new_to_check.add(dep) - depends.add(dep) - return depends - -def field_dependencies(field, checked_models=None): - checked_models = checked_models or set() - depends = set() - arg_defs, kwarg_defs = modelsinspector.matching_details(field) - for attrname, options in arg_defs + list(kwarg_defs.values()): - if options.get("ignore_if_auto_through", False) and auto_through(field): - continue - if options.get("is_value", False): - value = attrname - elif attrname == 'rel.through' and hasattr(getattr(field, 'rel', None), 'through_model'): - # Hack for django 1.1 and below, where the through model is stored - # in rel.through_model while rel.through stores only the model name. - value = field.rel.through_model - else: - try: - value = get_attribute(field, attrname) - except AttributeError: - if options.get("ignore_missing", False): - continue - raise - if isinstance(value, Model): - value = value.__class__ - if not isinstance(value, ModelBase): - continue - if getattr(value._meta, "proxy", False): - value = value._meta.proxy_for_model - if value in checked_models: - continue - checked_models.add(value) - depends.add(value) - depends.update(model_dependencies(value, checked_models)) - - return depends - -### Prettyprinters - -def pprint_frozen_models(models): - return "{\n %s\n }" % ",\n ".join([ - "%r: %s" % (name, pprint_fields(fields)) - for name, fields in sorted(models.items()) - ]) - -def pprint_fields(fields): - return "{\n %s\n }" % ",\n ".join([ - "%r: %r" % (name, defn) - for name, defn in sorted(fields.items()) - ]) - -### Output sanitisers - -USELESS_KEYWORDS = ["choices", "help_text", "verbose_name"] -USELESS_DB_KEYWORDS = ["related_name", "default", "blank"] # Important for ORM, not for DB. -INDEX_KEYWORDS = ["db_index"] - -def remove_useless_attributes(field, db=False, indexes=False): - "Removes useless (for database) attributes from the field's defn." - # Work out what to remove, and remove it. - keywords = USELESS_KEYWORDS[:] - if db: - keywords += USELESS_DB_KEYWORDS[:] - if indexes: - keywords += INDEX_KEYWORDS[:] - if field: - for name in keywords: - if name in field[2]: - del field[2][name] - return field - -USELESS_META = ["verbose_name", "verbose_name_plural"] -def remove_useless_meta(meta): - "Removes useless (for database) attributes from the table's meta." - if meta: - for name in USELESS_META: - if name in meta: - del meta[name] - return meta |