#28980: Make the autodetector validate the type of one-off default values
--------------------------------------+------------------------------------
     Reporter:  Nikos Katsos          |                    Owner:  Jeff
         Type:  Cleanup/optimization  |                   Status:  assigned
    Component:  Migrations            |                  Version:  2.0
     Severity:  Normal                |               Resolution:
     Keywords:                        |             Triage Stage:  Accepted
    Has patch:  0                     |      Needs documentation:  0
  Needs tests:  0                     |  Patch needs improvement:  0
Easy pickings:  0                     |                    UI/UX:  0
--------------------------------------+------------------------------------

Comment (by Jeff):

 If anyone is willing to give me a hand, I am close to a viable patch, see
 
[https://github.com/jeffyancey/django/commit/a6b9ee29e06ae10c8eda58a21485ad833a241adc
 commit], however I am currently wrangling with an existing test
 `tests/migrations/test_commands.py` -
 `MakeMigrationsTests.test_makemigrations_auto_now_add_interactive`. The
 test is failing like so:

 {{{
 ======================================================================
 ERROR: test_makemigrations_auto_now_add_interactive
 (migrations.test_commands.MakeMigrationsTests)
 ----------------------------------------------------------------------
 Traceback (most recent call last):
   File "/usr/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
     yield
   File "/usr/lib/python3.6/unittest/case.py", line 605, in run
     testMethod()
   File "/usr/lib/python3.6/unittest/mock.py", line 1179, in patched
     return func(*args, **keywargs)
   File "/home/jy/Django/forks/django-
 repo/tests/migrations/test_commands.py", line 1300, in
 test_makemigrations_auto_now_add_interactive
     call_command('makemigrations', 'migrations', interactive=True,
 stdout=out)
   File "/home/jy/Django/forks/django-
 repo/django/core/management/__init__.py", line 148, in call_command
     return command.execute(*args, **defaults)
   File "/home/jy/Django/forks/django-repo/django/core/management/base.py",
 line 354, in execute
     output = self.handle(*args, **options)
   File "/home/jy/Django/forks/django-repo/django/core/management/base.py",
 line 83, in wrapped
     res = handle_func(*args, **kwargs)
   File "/home/jy/Django/forks/django-
 repo/django/core/management/commands/makemigrations.py", line 161, in
 handle
     migration_name=self.migration_name,
   File "/home/jy/Django/forks/django-
 repo/django/db/migrations/autodetector.py", line 44, in changes
     changes = self._detect_changes(convert_apps, graph)
   File "/home/jy/Django/forks/django-
 repo/django/db/migrations/autodetector.py", line 183, in _detect_changes
     self.generate_added_fields()
   File "/home/jy/Django/forks/django-
 repo/django/db/migrations/autodetector.py", line 835, in
 generate_added_fields
     self._generate_added_field(app_label, model_name, field_name)
   File "/home/jy/Django/forks/django-
 repo/django/db/migrations/autodetector.py", line 854, in
 _generate_added_field
     field.default = self.questioner.ask_auto_now_add_addition(field,
 model_name)
   File "/home/jy/Django/forks/django-
 repo/django/db/migrations/questioner.py", line 224, in
 ask_auto_now_add_addition
     return self._ask_default(field_instance, default='timezone.now')
   File "/home/jy/Django/forks/django-
 repo/django/db/migrations/questioner.py", line 139, in _ask_default
     if field_instance.to_python(code):
   File "/home/jy/Django/forks/django-
 repo/django/db/models/fields/__init__.py", line 1369, in to_python
     parsed = parse_datetime(value)
   File "/home/jy/Django/forks/django-repo/django/utils/dateparse.py", line
 106, in parse_datetime
     match = datetime_re.match(value)
 TypeError: expected string or bytes-like object
 }}}

 I have confirmed that at this point the value being passed to `to_python`
 is the integer 1, which should indeed be an invalid default/one-off value
 to pass for a DateTime field.

 At the moment what seems to be blocking me, I believe, is figuring out how
 `unittest.mock.patch()` works, and how that value is being set for the
 interactive test:

 {{{
 @mock.patch('builtins.input', return_value='1')
 @mock.patch('django.db.migrations.questioner.sys.stdin',
 mock.MagicMock(encoding=sys.getdefaultencoding()))
 def test_makemigrations_auto_now_add_interactive(self, *args):
     """
     makemigrations prompts the user when adding auto_now_add to an
 existing
     model.
     """
     class Entry(models.Model):
         title = models.CharField(max_length=255)
         creation_date = models.DateTimeField(auto_now_add=True)

         class Meta:
             app_label = 'migrations'

     # Monkeypatch interactive questioner to auto accept
     with mock.patch('django.db.migrations.questioner.sys.stdout',
 new_callable=io.StringIO) as prompt_stdout:
         out = io.StringIO()
         with
 self.temporary_migration_module(module='migrations.test_auto_now_add'):
             call_command('makemigrations', 'migrations', interactive=True,
 stdout=out)
         output = out.getvalue()
         prompt_output = prompt_stdout.getvalue()
         self.assertIn("You can accept the default 'timezone.now' by
 pressing 'Enter'", prompt_output)
         self.assertIn("Add field creation_date to entry", output)
 }}}

 If anyone could provide some guidance on how to properly work with this
 test, I'd appreciate it.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/28980#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/064.e44425ddf8d2f237a4634a26bee368fb%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to