Skip to content

Commit

Permalink
Made createsuperuser more robust when getting current OS username.
Browse files Browse the repository at this point in the history
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 django#16017.
  • Loading branch information
ramiro committed Aug 18, 2012
1 parent 6e4c984 commit 4c934f3
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 14 deletions.
19 changes: 11 additions & 8 deletions django/contrib/auth/management/__init__.py
Expand Up @@ -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):
Expand Down
44 changes: 38 additions & 6 deletions 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):
Expand Down Expand Up @@ -111,3 +109,37 @@ def test_createsuperuser_management_command(self):
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')

0 comments on commit 4c934f3

Please sign in to comment.