summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/south/creator
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/south/creator')
-rw-r--r--lib/python2.7/site-packages/south/creator/__init__.py5
-rw-r--r--lib/python2.7/site-packages/south/creator/actions.py559
-rw-r--r--lib/python2.7/site-packages/south/creator/changes.py506
-rw-r--r--lib/python2.7/site-packages/south/creator/freezer.py192
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