From 4c934f3921a59c7b3e088f6472b6f6da40848567 Mon Sep 17 00:00:00 2001 From: Ramiro Morales Date: Fri, 17 Aug 2012 23:15:20 -0300 Subject: [PATCH] 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. --- django/contrib/auth/management/__init__.py | 19 ++++++---- django/contrib/auth/tests/basic.py | 44 +++++++++++++++++++--- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/django/contrib/auth/management/__init__.py b/django/contrib/auth/management/__init__.py index 7dcbfe4746..83e1518387 100644 --- a/django/contrib/auth/management/__init__.py +++ b/django/contrib/auth/management/__init__.py @@ -84,14 +84,17 @@ def get_system_username(): :returns: The username as a unicode string, or an empty string if the username could not be determined. """ - try: - return getpass.getuser().decode(locale.getdefaultlocale()[1]) - 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. - return '' + default_locale = locale.getdefaultlocale()[1] + if default_locale: + try: + 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 '' def get_default_username(check_db=True): diff --git a/django/contrib/auth/tests/basic.py b/django/contrib/auth/tests/basic.py index 21acb2004f..710754b8f1 100644 --- a/django/contrib/auth/tests/basic.py +++ b/django/contrib/auth/tests/basic.py @@ -1,13 +1,11 @@ +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')