Opened 3 weeks ago

Closed 3 weeks ago

#28772 closed Cleanup/optimization (wontfix)

UnicodeWarning produced when using callable default on BinaryField in Python 2

Reported by: Tim Dawborn Owned by: nobody
Component: Database layer (models, ORM) Version: 1.8
Severity: Normal Keywords: UnicodeWarning BinaryField
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

This affects versions all the way back from 1.8 and the rest of the 1.x series (the issue tracker only lets me go back to 1.8). This only happens when running under Python 2.

When using a callable default value to a BinaryField instance, a UnicodeWarning is produced due to the comparison of the return value of default against a Unicode string (from https://github.com/django/django/blob/master/django/db/models/fields/__init__.py#L2306):

class BinaryField(Field):
    ...
    def get_default(self):
        if self.has_default() and not callable(self.default):
            return self.default
        default = super(BinaryField, self).get_default()
        if default == '':
            return b''
        return default

I've created a blank Django project called foo and created an app called bar. In there, I've created a model called Baz which has a BinaryField with a callable default.

$ cat bar/models.py
import os

from django.db import models


def my_default():
    return os.urandom(12)


class Baz(models.Model):
    my_field = models.BinaryField(default=my_default)

I have two virtualenvs setup — one running Python 2.7 and one running 3.6. Both have Django 1.11 installed:

$ ../ve2/bin/pip install -q --upgrade 'django<2'
$ ../ve3/bin/pip install -q --upgrade 'django<2'

When running under Python 2, Django versions 1.8 through 1.11 (all minor versions inclusive) produce a UnicodeWarning when deprecation warnings are enabled:

$ ../ve2/bin/python -W default manage.py shell -c 'from bar.models import Baz; b = Baz()'
/private/tmp/django/ve2/lib/python2.7/site-packages/django/db/models/fields/__init__.py:2343: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
  if default == '':
$ ../ve3/bin/python -W default manage.py shell -c 'from bar.models import Baz; b = Baz()'
$

This could be fixed by doing a type check on the returned value of the callable to see if it is of type six.text_type a la https://docs.djangoproject.com/en/1.11/topics/python3/#string-handling-with-six:

class BinaryField(Field):
    ...
    def get_default(self):
        if self.has_default() and not callable(self.default):
            return self.default
        default = super(BinaryField, self).get_default()
        if isinstance(default, six.text_type) and default == '':
            return b''
        return default

Change History (1)

comment:1 Changed 3 weeks ago by Tim Graham

Resolution: wontfix
Status: newclosed
Type: UncategorizedCleanup/optimization

#23222 is related. As Django's master branch (and the upcoming 2.0 release) no longer support Python 2 and this issue doesn't qualify for a backport to 1.11 as per our supported versions policy, we won't fix it.

Note: See TracTickets for help on using tickets.
Back to Top