Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(3132)

Unified Diff: venv/Lib/site-packages/django/db/migrations/questioner.py

Issue 554060043: testMe
Patch Set: Created 2 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: venv/Lib/site-packages/django/db/migrations/questioner.py
===================================================================
new file mode 100644
--- /dev/null
+++ b/venv/Lib/site-packages/django/db/migrations/questioner.py
@@ -0,0 +1,246 @@
+from __future__ import print_function, unicode_literals
+
+import importlib
+import os
+import sys
+
+from django.apps import apps
+from django.db.models.fields import NOT_PROVIDED
+from django.utils import datetime_safe, six, timezone
+from django.utils.six.moves import input
+
+from .loader import MigrationLoader
+
+
+class MigrationQuestioner(object):
+ """
+ Gives the autodetector responses to questions it might have.
+ This base class has a built-in noninteractive mode, but the
+ interactive subclass is what the command-line arguments will use.
+ """
+
+ def __init__(self, defaults=None, specified_apps=None, dry_run=None):
+ self.defaults = defaults or {}
+ self.specified_apps = specified_apps or set()
+ self.dry_run = dry_run
+
+ def ask_initial(self, app_label):
+ "Should we create an initial migration for the app?"
+ # If it was specified on the command line, definitely true
+ if app_label in self.specified_apps:
+ return True
+ # Otherwise, we look to see if it has a migrations module
+ # without any Python files in it, apart from __init__.py.
+ # Apps from the new app template will have these; the python
+ # file check will ensure we skip South ones.
+ try:
+ app_config = apps.get_app_config(app_label)
+ except LookupError: # It's a fake app.
+ return self.defaults.get("ask_initial", False)
+ migrations_import_path, _ = MigrationLoader.migrations_module(app_config.label)
+ if migrations_import_path is None:
+ # It's an application with migrations disabled.
+ return self.defaults.get("ask_initial", False)
+ try:
+ migrations_module = importlib.import_module(migrations_import_path)
+ except ImportError:
+ return self.defaults.get("ask_initial", False)
+ else:
+ # getattr() needed on PY36 and older (replace with attribute access).
+ if getattr(migrations_module, "__file__", None):
+ filenames = os.listdir(os.path.dirname(migrations_module.__file__))
+ elif hasattr(migrations_module, "__path__"):
+ if len(migrations_module.__path__) > 1:
+ return False
+ filenames = os.listdir(list(migrations_module.__path__)[0])
+ return not any(x.endswith(".py") for x in filenames if x != "__init__.py")
+
+ def ask_not_null_addition(self, field_name, model_name):
+ "Adding a NOT NULL field to a model"
+ # None means quit
+ return None
+
+ def ask_not_null_alteration(self, field_name, model_name):
+ "Changing a NULL field to NOT NULL"
+ # None means quit
+ return None
+
+ def ask_rename(self, model_name, old_name, new_name, field_instance):
+ "Was this field really renamed?"
+ return self.defaults.get("ask_rename", False)
+
+ def ask_rename_model(self, old_model_state, new_model_state):
+ "Was this model really renamed?"
+ return self.defaults.get("ask_rename_model", False)
+
+ def ask_merge(self, app_label):
+ "Do you really want to merge these migrations?"
+ return self.defaults.get("ask_merge", False)
+
+ def ask_auto_now_add_addition(self, field_name, model_name):
+ "Adding an auto_now_add field to a model"
+ # None means quit
+ return None
+
+
+class InteractiveMigrationQuestioner(MigrationQuestioner):
+
+ def _boolean_input(self, question, default=None):
+ result = input("%s " % question)
+ if not result and default is not None:
+ return default
+ while len(result) < 1 or result[0].lower() not in "yn":
+ result = input("Please answer yes or no: ")
+ return result[0].lower() == "y"
+
+ def _choice_input(self, question, choices):
+ print(question)
+ for i, choice in enumerate(choices):
+ print(" %s) %s" % (i + 1, choice))
+ result = input("Select an option: ")
+ while True:
+ try:
+ value = int(result)
+ if 0 < value <= len(choices):
+ return value
+ except ValueError:
+ pass
+ result = input("Please select a valid option: ")
+
+ def _ask_default(self, default=''):
+ """
+ Prompt for a default value.
+
+ The ``default`` argument allows providing a custom default value (as a
+ string) which will be shown to the user and used as the return value
+ if the user doesn't provide any other input.
+ """
+ print("Please enter the default value now, as valid Python")
+ if default:
+ print(
+ "You can accept the default '{}' by pressing 'Enter' or you "
+ "can provide another value.".format(default)
+ )
+ print("The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now")
+ print("Type 'exit' to exit this prompt")
+ while True:
+ if default:
+ prompt = "[default: {}] >>> ".format(default)
+ else:
+ prompt = ">>> "
+ if six.PY3:
+ # Six does not correctly abstract over the fact that
+ # py3 input returns a unicode string, while py2 raw_input
+ # returns a bytestring.
+ code = input(prompt)
+ else:
+ code = input(prompt).decode(sys.stdin.encoding)
+ if not code and default:
+ code = default
+ if not code:
+ print("Please enter some code, or 'exit' (with no quotes) to exit.")
+ elif code == "exit":
+ sys.exit(1)
+ else:
+ try:
+ return eval(code, {}, {"datetime": datetime_safe, "timezone": timezone})
+ except (SyntaxError, NameError) as e:
+ print("Invalid input: %s" % e)
+
+ def ask_not_null_addition(self, field_name, model_name):
+ "Adding a NOT NULL field to a model"
+ if not self.dry_run:
+ choice = self._choice_input(
+ "You are trying to add a non-nullable field '%s' to %s without a default; "
+ "we can't do that (the database needs something to populate existing rows).\n"
+ "Please select a fix:" % (field_name, model_name),
+ [
+ ("Provide a one-off default now (will be set on all existing "
+ "rows with a null value for this column)"),
+ "Quit, and let me add a default in models.py",
+ ]
+ )
+ if choice == 2:
+ sys.exit(3)
+ else:
+ return self._ask_default()
+ return None
+
+ def ask_not_null_alteration(self, field_name, model_name):
+ "Changing a NULL field to NOT NULL"
+ if not self.dry_run:
+ choice = self._choice_input(
+ "You are trying to change the nullable field '%s' on %s to non-nullable "
+ "without a default; we can't do that (the database needs something to "
+ "populate existing rows).\n"
+ "Please select a fix:" % (field_name, model_name),
+ [
+ ("Provide a one-off default now (will be set on all existing "
+ "rows with a null value for this column)"),
+ ("Ignore for now, and let me handle existing rows with NULL myself "
+ "(e.g. because you added a RunPython or RunSQL operation to handle "
+ "NULL values in a previous data migration)"),
+ "Quit, and let me add a default in models.py",
+ ]
+ )
+ if choice == 2:
+ return NOT_PROVIDED
+ elif choice == 3:
+ sys.exit(3)
+ else:
+ return self._ask_default()
+ return None
+
+ def ask_rename(self, model_name, old_name, new_name, field_instance):
+ "Was this field really renamed?"
+ msg = "Did you rename %s.%s to %s.%s (a %s)? [y/N]"
+ return self._boolean_input(msg % (model_name, old_name, model_name, new_name,
+ field_instance.__class__.__name__), False)
+
+ def ask_rename_model(self, old_model_state, new_model_state):
+ "Was this model really renamed?"
+ msg = "Did you rename the %s.%s model to %s? [y/N]"
+ return self._boolean_input(msg % (old_model_state.app_label, old_model_state.name,
+ new_model_state.name), False)
+
+ def ask_merge(self, app_label):
+ return self._boolean_input(
+ "\nMerging will only work if the operations printed above do not conflict\n" +
+ "with each other (working on different fields or models)\n" +
+ "Do you want to merge these migration branches? [y/N]",
+ False,
+ )
+
+ def ask_auto_now_add_addition(self, field_name, model_name):
+ "Adding an auto_now_add field to a model"
+ if not self.dry_run:
+ choice = self._choice_input(
+ "You are trying to add the field '{}' with 'auto_now_add=True' "
+ "to {} without a default; the database needs something to "
+ "populate existing rows.\n".format(field_name, model_name),
+ [
+ "Provide a one-off default now (will be set on all "
+ "existing rows)",
+ "Quit, and let me add a default in models.py",
+ ]
+ )
+ if choice == 2:
+ sys.exit(3)
+ else:
+ return self._ask_default(default='timezone.now')
+ return None
+
+
+class NonInteractiveMigrationQuestioner(MigrationQuestioner):
+
+ def ask_not_null_addition(self, field_name, model_name):
+ # We can't ask the user, so act like the user aborted.
+ sys.exit(3)
+
+ def ask_not_null_alteration(self, field_name, model_name):
+ # We can't ask the user, so set as not provided.
+ return NOT_PROVIDED
+
+ def ask_auto_now_add_addition(self, field_name, model_name):
+ # We can't ask the user, so act like the user aborted.
+ sys.exit(3)
« no previous file with comments | « venv/Lib/site-packages/django/db/migrations/optimizer.py ('k') | venv/Lib/site-packages/django/db/migrations/recorder.py » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b