diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 39fc975..1c232c9 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -552,10 +552,7 @@ class InteractiveShell(SingletonConfigurable, Magic): 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 @@ class InteractiveShell(SingletonConfigurable, Magic): # 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) diff --git a/IPython/utils/path.py b/IPython/utils/path.py index cc54397..3fc6a6f 100644 --- a/IPython/utils/path.py +++ b/IPython/utils/path.py @@ -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: diff --git a/IPython/utils/tests/test_path.py b/IPython/utils/tests/test_path.py index 3b00a81..815542e 100644 --- a/IPython/utils/tests/test_path.py +++ b/IPython/utils/tests/test_path.py @@ -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?