Commit 4c934f39 authored by Ramiro Morales's avatar Ramiro Morales
Browse files

Made createsuperuser more robust when getting current OS username.

Under some versions of OS X, failure in getting the default system
locale during the syncdb operation of the auth app were causing hard to
diagnose problems afterwards.

No solution based on getpreferredencoding() was chosen because it has
its own problems with certain combinations of Python and OS X versions
(e.g. http://bugs.python.org/issue6202).

Thanks prestonsimmons for the report and prestonsimmons and willhardy
for the initial patch.

Fixes #16017.
parent 6e4c9840
Loading
Loading
Loading
Loading
+11 −8
Original line number Diff line number Diff line
@@ -84,13 +84,16 @@ def get_system_username():
    :returns: The username as a unicode string, or an empty string if the
        username could not be determined.
    """
    default_locale = locale.getdefaultlocale()[1]
    if default_locale:
        try:
        return getpass.getuser().decode(locale.getdefaultlocale()[1])
            return getpass.getuser().decode(default_locale)
        except (ImportError, KeyError, UnicodeDecodeError):
            # KeyError will be raised by os.getpwuid() (called by getuser())
            # if there is no corresponding entry in the /etc/passwd file
            # (a very restricted chroot environment, for example).
            # UnicodeDecodeError - preventive treatment for non-latin Windows.
            pass
    return ''


+38 −6
Original line number Diff line number Diff line
import locale
import traceback

from django.contrib.auth.management.commands import createsuperuser
from django.contrib.auth.models import User, AnonymousUser
from django.core.management import call_command
from django.test import TestCase
from django.utils.six import StringIO
from django.utils.unittest import skipUnless

try:
    import crypt as crypt_module
except ImportError:
    crypt_module = None


class BasicTestCase(TestCase):
@@ -111,3 +109,37 @@ class BasicTestCase(TestCase):
        u = User.objects.get(username="joe+admin@somewhere.org")
        self.assertEqual(u.email, 'joe@somewhere.org')
        self.assertFalse(u.has_usable_password())

    def test_createsuperuser_nolocale(self):
        """
        Check that createsuperuser does not break when no locale is set. See
        ticket #16017.
        """

        old_getdefaultlocale = locale.getdefaultlocale
        old_getpass = createsuperuser.getpass
        try:
            # Temporarily remove locale information
            locale.getdefaultlocale = lambda: (None, None)

            # Temporarily replace getpass to allow interactive code to be used
            # non-interactively
            class mock_getpass: pass
            mock_getpass.getpass = staticmethod(lambda p=None: "nopasswd")
            createsuperuser.getpass = mock_getpass

            # Call the command in this new environment
            new_io = StringIO()
            call_command("createsuperuser", interactive=True, username="nolocale@somewhere.org", email="nolocale@somewhere.org", stdout=new_io)

        except TypeError as e:
            self.fail("createsuperuser fails if the OS provides no information about the current locale")

        finally:
            # Re-apply locale and getpass information
            createsuperuser.getpass = old_getpass
            locale.getdefaultlocale = old_getdefaultlocale

        # If we were successful, a user should have been created
        u = User.objects.get(username="nolocale@somewhere.org")
        self.assertEqual(u.email, 'nolocale@somewhere.org')