Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

defer to stdlib for path.get_home_dir() #998

Merged
merged 3 commits into from
Nov 24, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions IPython/core/interactiveshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,10 +552,7 @@ def init_syntax_highlighting(self):

def init_pushd_popd_magic(self):
# for pushd/popd management
try:
self.home_dir = get_home_dir()
except HomeDirError, msg:
fatal(msg)
self.home_dir = get_home_dir()

self.dir_stack = []

Expand Down Expand Up @@ -1751,12 +1748,10 @@ def init_readline(self):
# Or if libedit is used, load editrc.
inputrc_name = os.environ.get('INPUTRC')
if inputrc_name is None:
home_dir = get_home_dir()
if home_dir is not None:
inputrc_name = '.inputrc'
if readline.uses_libedit:
inputrc_name = '.editrc'
inputrc_name = os.path.join(home_dir, inputrc_name)
inputrc_name = '.inputrc'
if readline.uses_libedit:
inputrc_name = '.editrc'
inputrc_name = os.path.join(self.home_dir, inputrc_name)
if os.path.isfile(inputrc_name):
try:
readline.read_init_file(inputrc_name)
Expand Down
120 changes: 30 additions & 90 deletions IPython/utils/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,23 +167,25 @@ class HomeDirError(Exception):
pass


def get_home_dir():
"""Return the closest possible equivalent to a 'home' directory.

* On POSIX, we try $HOME.
* On Windows we try:
- %HOMESHARE%
- %HOMEDRIVE\%HOMEPATH%
- %USERPROFILE%
- Registry hack for My Documents
- %HOME%: rare, but some people with unix-like setups may have defined it
* On Dos C:\

Currently only Posix and NT are implemented, a HomeDirError exception is
raised for all other OSes.
"""
def get_home_dir(require_writable=False):
"""Return the 'home' directory, as a unicode string.

env = os.environ
* First, check for frozen env in case of py2exe
* Otherwise, defer to os.path.expanduser('~')

See stdlib docs for how this is determined.
$HOME is first priority on *ALL* platforms.

Parameters
----------

require_writable : bool [default: False]
if True:
guarantees the return value is a writable directory, otherwise
raises HomeDirError
if False:
The path is resolved, but it is not guaranteed to exist or be writable.
"""

# first, check py2exe distribution root directory for _ipython.
# This overrides all. Normally does not exist.
Expand All @@ -197,59 +199,11 @@ def get_home_dir():
if _writable_dir(os.path.join(root, '_ipython')):
os.environ["IPYKITROOT"] = root
return py3compat.cast_unicode(root, fs_encoding)

if os.name == 'posix':
# Linux, Unix, AIX, OS X
try:
homedir = env['HOME']
except KeyError:
# Last-ditch attempt at finding a suitable $HOME, on systems where
# it may not be defined in the environment but the system shell
# still knows it - reported once as:
# https://github.com/ipython/ipython/issues/154
from subprocess import Popen, PIPE
homedir = Popen('echo $HOME', shell=True,
stdout=PIPE).communicate()[0].strip()
if homedir:
return py3compat.cast_unicode(homedir, fs_encoding)
else:
raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
else:
return py3compat.cast_unicode(homedir, fs_encoding)
elif os.name == 'nt':
# Now for win9x, XP, Vista, 7?
# For some strange reason all of these return 'nt' for os.name.
# First look for a network home directory. This will return the UNC
# path (\\server\\Users\%username%) not the mapped path (Z:\). This
# is needed when running IPython on cluster where all paths have to
# be UNC.
try:
homedir = env['HOMESHARE']
except KeyError:
pass
else:
if _writable_dir(homedir):
return py3compat.cast_unicode(homedir, fs_encoding)

# Now look for a local home directory
try:
homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
except KeyError:
pass
else:
if _writable_dir(homedir):
return py3compat.cast_unicode(homedir, fs_encoding)

# Now the users profile directory
try:
homedir = os.path.join(env['USERPROFILE'])
except KeyError:
pass
else:
if _writable_dir(homedir):
return py3compat.cast_unicode(homedir, fs_encoding)

# Use the registry to get the 'My Documents' folder.

homedir = os.path.expanduser('~')

if not _writable_dir(homedir) and os.name == 'nt':
# expanduser failed, use the registry to get the 'My Documents' folder.
try:
import _winreg as wreg
key = wreg.OpenKey(
Expand All @@ -260,27 +214,12 @@ def get_home_dir():
key.Close()
except:
pass
else:
if _writable_dir(homedir):
return py3compat.cast_unicode(homedir, fs_encoding)

# A user with a lot of unix tools in win32 may have defined $HOME.
# Try this as a last ditch option.
try:
homedir = env['HOME']
except KeyError:
pass
else:
if _writable_dir(homedir):
return py3compat.cast_unicode(homedir, fs_encoding)

# If all else fails, raise HomeDirError
raise HomeDirError('No valid home directory could be found')
elif os.name == 'dos':
# Desperate, may do absurd things in classic MacOS. May work under DOS.
return u'C:\\'

if (not require_writable) or _writable_dir(homedir):
return py3compat.cast_unicode(homedir, fs_encoding)
else:
raise HomeDirError('No valid home directory could be found for your OS')
raise HomeDirError('%s is not a writable dir, '
'set $HOME environment variable to override' % homedir)

def get_xdg_dir():
"""Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
Expand All @@ -292,7 +231,7 @@ def get_xdg_dir():

if os.name == 'posix':
# Linux, Unix, AIX, OS X
# use ~/.config if not set OR empty
# use ~/.config if empty OR not set
xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
if xdg and _writable_dir(xdg):
return py3compat.cast_unicode(xdg, fs_encoding)
Expand All @@ -316,6 +255,7 @@ def get_ipython_dir():

home_dir = get_home_dir()
xdg_dir = get_xdg_dir()

# import pdb; pdb.set_trace() # dbg
ipdir = env.get('IPYTHON_DIR', env.get('IPYTHONDIR', None))
if ipdir is None:
Expand Down
62 changes: 12 additions & 50 deletions IPython/utils/tests/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ def teardown_environment():
# Build decorator that uses the setup_environment/setup_environment
with_environment = with_setup(setup_environment, teardown_environment)


@skip_if_not_win32
@with_environment
def test_get_home_dir_1():
Expand All @@ -142,71 +141,34 @@ def test_get_home_dir_2():
#fake filename for IPython.__init__
IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()

home_dir = path.get_home_dir()
home_dir = path.get_home_dir(True)
nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower())


@with_environment
@skip_win32
def test_get_home_dir_3():
"""Testcase $HOME is set, then use its value as home directory."""
"""get_home_dir() uses $HOME if set"""
env["HOME"] = HOME_TEST_DIR
home_dir = path.get_home_dir()
home_dir = path.get_home_dir(True)
nt.assert_equal(home_dir, env["HOME"])


@with_environment
@skip_win32
def test_get_home_dir_4():
"""Testcase $HOME is not set, os=='posix'.
This should fail with HomeDirError"""
"""get_home_dir() still works if $HOME is not set"""

os.name = 'posix'
if 'HOME' in env: del env['HOME']
nt.assert_raises(path.HomeDirError, path.get_home_dir)
# this should still succeed, but we don't know what the answer should be
home = path.get_home_dir(True)
nt.assert_true(path._writable_dir(home))


@skip_if_not_win32
@with_environment
def test_get_home_dir_5():
"""Using HOMEDRIVE + HOMEPATH, os=='nt'.

HOMESHARE is missing.
"""

os.name = 'nt'
env.pop('HOMESHARE', None)
env['HOMEDRIVE'], env['HOMEPATH'] = os.path.splitdrive(HOME_TEST_DIR)
home_dir = path.get_home_dir()
nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))


@skip_if_not_win32
@with_environment
def test_get_home_dir_6():
"""Using USERPROFILE, os=='nt'.

HOMESHARE, HOMEDRIVE, HOMEPATH are missing.
"""

os.name = 'nt'
env.pop('HOMESHARE', None)
env.pop('HOMEDRIVE', None)
env.pop('HOMEPATH', None)
env["USERPROFILE"] = abspath(HOME_TEST_DIR)
home_dir = path.get_home_dir()
nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))


@skip_if_not_win32
@with_environment
def test_get_home_dir_7():
"""Using HOMESHARE, os=='nt'."""

os.name = 'nt'
env["HOMESHARE"] = abspath(HOME_TEST_DIR)
home_dir = path.get_home_dir()
nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
"""raise HomeDirError if $HOME is specified, but not a writable dir"""
env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
# set os.name = posix, to prevent My Documents fallback on Windows
os.name = 'posix'
nt.assert_raises(path.HomeDirError, path.get_home_dir, True)


# Should we stub wreg fully so we can run the test on all platforms?
Expand Down