Permalink
Browse files

Merge pull request #998 from minrk/homedir

defer to stdlib os.path.expanduser('~') for path.get_home_dir()

frozen env still comes first, and My Documents registry query is fallback on Windows, but in all normal cases, expanduser is used, which has $HOME as first priority.

IPython also no longer considers finding no writable home dir as a fatal error.

closes #810
closes #747
closes #970
  • Loading branch information...
2 parents c82649e + 9df2cbb commit 351c8fc4334a266a8e70c841e58afe8bfa0f51ea @minrk minrk committed Nov 24, 2011
Showing with 47 additions and 150 deletions.
  1. +5 −10 IPython/core/interactiveshell.py
  2. +30 −90 IPython/utils/path.py
  3. +12 −50 IPython/utils/tests/test_path.py
@@ -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 = []
@@ -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)
View
@@ -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.
@@ -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(
@@ -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.
@@ -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)
@@ -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:
@@ -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():
@@ -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?

0 comments on commit 351c8fc

Please sign in to comment.