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.
This commit is contained in:
Ramiro Morales 2012-08-17 23:15:20 -03:00
parent 6e4c984098
commit 4c934f3921
2 changed files with 49 additions and 14 deletions

View File

@ -84,14 +84,17 @@ def get_system_username():
:returns: The username as a unicode string, or an empty string if the :returns: The username as a unicode string, or an empty string if the
username could not be determined. username could not be determined.
""" """
try: default_locale = locale.getdefaultlocale()[1]
return getpass.getuser().decode(locale.getdefaultlocale()[1]) if default_locale:
except (ImportError, KeyError, UnicodeDecodeError): try:
# KeyError will be raised by os.getpwuid() (called by getuser()) return getpass.getuser().decode(default_locale)
# if there is no corresponding entry in the /etc/passwd file except (ImportError, KeyError, UnicodeDecodeError):
# (a very restricted chroot environment, for example). # KeyError will be raised by os.getpwuid() (called by getuser())
# UnicodeDecodeError - preventive treatment for non-latin Windows. # if there is no corresponding entry in the /etc/passwd file
return '' # (a very restricted chroot environment, for example).
# UnicodeDecodeError - preventive treatment for non-latin Windows.
pass
return ''
def get_default_username(check_db=True): def get_default_username(check_db=True):

View File

@ -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.contrib.auth.models import User, AnonymousUser
from django.core.management import call_command from django.core.management import call_command
from django.test import TestCase from django.test import TestCase
from django.utils.six import StringIO 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): class BasicTestCase(TestCase):
@ -111,3 +109,37 @@ class BasicTestCase(TestCase):
u = User.objects.get(username="joe+admin@somewhere.org") u = User.objects.get(username="joe+admin@somewhere.org")
self.assertEqual(u.email, 'joe@somewhere.org') self.assertEqual(u.email, 'joe@somewhere.org')
self.assertFalse(u.has_usable_password()) 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')