Commit b50b33b4 authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

bpo-10496: posixpath.expanduser() catchs pwd.getpwuid() error (GH-10919) (GH-10930)

* posixpath.expanduser() now returns the input path unchanged if
  the HOME environment variable is not set and pwd.getpwuid() raises
  KeyError (the current user identifier doesn't exist in the password
  database).
* Add test_no_home_directory() to test_site.

(cherry picked from commit f2f4555d)
parent bacc272a
......@@ -259,7 +259,12 @@ def expanduser(path):
if i == 1:
if 'HOME' not in os.environ:
import pwd
userhome = pwd.getpwuid(os.getuid()).pw_dir
try:
userhome = pwd.getpwuid(os.getuid()).pw_dir
except KeyError:
# bpo-10496: if the current user identifier doesn't exist in the
# password database, return the path unchanged
return path
else:
userhome = os.environ['HOME']
else:
......@@ -267,6 +272,8 @@ def expanduser(path):
try:
pwent = pwd.getpwnam(path[1:i])
except KeyError:
# bpo-10496: if the user name from the path doesn't exist in the
# password database, return the path unchanged
return path
userhome = pwent.pw_dir
userhome = userhome.rstrip('/')
......
......@@ -262,34 +262,56 @@ class PosixPathTest(unittest.TestCase):
def test_expanduser(self):
self.assertEqual(posixpath.expanduser("foo"), "foo")
with test_support.EnvironmentVarGuard() as env:
def test_expanduser_home_envvar(self):
with support.EnvironmentVarGuard() as env:
env['HOME'] = '/home/victor'
self.assertEqual(posixpath.expanduser("~"), "/home/victor")
# expanduser() strips trailing slash
env['HOME'] = '/home/victor/'
self.assertEqual(posixpath.expanduser("~"), "/home/victor")
for home in '/', '', '//', '///':
env['HOME'] = home
self.assertEqual(posixpath.expanduser("~"), "/")
self.assertEqual(posixpath.expanduser("~/"), "/")
self.assertEqual(posixpath.expanduser("~/foo"), "/foo")
try:
import pwd
except ImportError:
pass
else:
self.assertIsInstance(posixpath.expanduser("~/"), basestring)
# if home directory == root directory, this test makes no sense
if posixpath.expanduser("~") != '/':
self.assertEqual(
posixpath.expanduser("~") + "/",
posixpath.expanduser("~/")
)
self.assertIsInstance(posixpath.expanduser("~root/"), basestring)
self.assertIsInstance(posixpath.expanduser("~foo/"), basestring)
with test_support.EnvironmentVarGuard() as env:
# expanduser should fall back to using the password database
del env['HOME']
home = pwd.getpwuid(os.getuid()).pw_dir
# $HOME can end with a trailing /, so strip it (see #17809)
home = home.rstrip("/") or '/'
self.assertEqual(posixpath.expanduser("~"), home)
def test_expanduser_pwd(self):
pwd = support.import_module('pwd')
self.assertIsInstance(posixpath.expanduser("~/"), str)
# if home directory == root directory, this test makes no sense
if posixpath.expanduser("~") != '/':
self.assertEqual(
posixpath.expanduser("~") + "/",
posixpath.expanduser("~/")
)
self.assertIsInstance(posixpath.expanduser("~root/"), str)
self.assertIsInstance(posixpath.expanduser("~foo/"), str)
with support.EnvironmentVarGuard() as env:
# expanduser should fall back to using the password database
del env['HOME']
home = pwd.getpwuid(os.getuid()).pw_dir
# $HOME can end with a trailing /, so strip it (see #17809)
home = home.rstrip("/") or '/'
self.assertEqual(posixpath.expanduser("~"), home)
# bpo-10496: If the HOME environment variable is not set and the
# user (current identifier or name in the path) doesn't exist in
# the password database (pwd.getuid() or pwd.getpwnam() fail),
# expanduser() must return the path unchanged.
def raise_keyerror(*args):
raise KeyError
with support.swap_attr(pwd, 'getpwuid', raise_keyerror), \
support.swap_attr(pwd, 'getpwnam', raise_keyerror):
for path in ('~', '~/.local', '~vstinner/'):
self.assertEqual(posixpath.expanduser(path), path)
def test_normpath(self):
self.assertEqual(posixpath.normpath(""), ".")
......
......@@ -7,6 +7,7 @@ executing have not been removed.
import unittest
from test.test_support import run_unittest, TESTFN, EnvironmentVarGuard
from test.test_support import captured_output
from test import support
import __builtin__
import errno
import os
......@@ -241,6 +242,7 @@ class HelperFunctionsTests(unittest.TestCase):
# the call sets USER_BASE *and* USER_SITE
self.assertEqual(site.USER_SITE, user_site)
self.assertTrue(user_site.startswith(site.USER_BASE), user_site)
self.assertEqual(site.USER_BASE, site.getuserbase())
def test_getsitepackages(self):
site.PREFIXES = ['xoxo']
......@@ -265,6 +267,48 @@ class HelperFunctionsTests(unittest.TestCase):
wanted = os.path.join('xoxo', 'lib', 'site-packages')
self.assertEqual(dirs[1], wanted)
def test_no_home_directory(self):
# bpo-10496: getuserbase() and getusersitepackages() must not fail if
# the current user has no home directory (if expanduser() returns the
# path unchanged).
site.USER_SITE = None
site.USER_BASE = None
sysconfig._CONFIG_VARS = None
with EnvironmentVarGuard() as environ, \
support.swap_attr(os.path, 'expanduser', lambda path: path):
del environ['PYTHONUSERBASE']
del environ['APPDATA']
user_base = site.getuserbase()
self.assertTrue(user_base.startswith('~' + os.sep),
user_base)
user_site = site.getusersitepackages()
self.assertTrue(user_site.startswith(user_base), user_site)
def fake_isdir(path):
fake_isdir.arg = path
return False
fake_isdir.arg = None
def must_not_be_called(*args):
raise AssertionError
with support.swap_attr(os.path, 'isdir', fake_isdir), \
support.swap_attr(site, 'addsitedir', must_not_be_called), \
support.swap_attr(site, 'ENABLE_USER_SITE', True):
# addusersitepackages() must not add user_site to sys.path
# if it is not an existing directory
known_paths = set()
site.addusersitepackages(known_paths)
self.assertEqual(fake_isdir.arg, user_site)
self.assertFalse(known_paths)
class PthFile(object):
"""Helper class for handling testing of .pth files"""
......
:func:`posixpath.expanduser` now returns the input *path* unchanged if the
``HOME`` environment variable is not set and the current user has no home
directory (if the current user identifier doesn't exist in the password
database). This change fix the :mod:`site` module if the current user doesn't
exist in the password database (if the user has no home directory).
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment