diff --git a/IPython/platutils.py b/IPython/platutils.py index 197d489..561e68d 100644 --- a/IPython/platutils.py +++ b/IPython/platutils.py @@ -88,6 +88,14 @@ def find_cmd(cmd): raise FindCmdError('command could not be found: %s' % cmd) return path +def get_long_path_name(path): + """Expand a path into its long form. + + On Windows this expands any ~ in the paths. On other platforms, it is + a null operation. + """ + return _platutils.get_long_path_name(path) + #----------------------------------------------------------------------------- # Deprecated functions #----------------------------------------------------------------------------- diff --git a/IPython/platutils_dummy.py b/IPython/platutils_dummy.py index 35aa5a0..0cb8965 100644 --- a/IPython/platutils_dummy.py +++ b/IPython/platutils_dummy.py @@ -27,3 +27,7 @@ def set_term_title(*args,**kw): def find_cmd(cmd): """Find the full path to a command using which.""" return os.popen('which %s' % cmd).read().strip() + +def get_long_path_name(path): + """Dummy no-op.""" + return path diff --git a/IPython/platutils_posix.py b/IPython/platutils_posix.py index d0700a2..b306479 100644 --- a/IPython/platutils_posix.py +++ b/IPython/platutils_posix.py @@ -34,3 +34,7 @@ else: def find_cmd(cmd): """Find the full path to a command using which.""" return os.popen('which %s' % cmd).read().strip() + +def get_long_path_name(path): + """Dummy no-op.""" + return path diff --git a/IPython/platutils_win32.py b/IPython/platutils_win32.py index 10fe9b9..66ae27f 100644 --- a/IPython/platutils_win32.py +++ b/IPython/platutils_win32.py @@ -54,3 +54,29 @@ def find_cmd(cmd): except: (path, offset) = win32api.SearchPath(os.environ['PATH'],cmd + '.bat') return path + + +def get_long_path_name(path): + """Get a long path name (expand ~) on Windows using ctypes. + + Examples + -------- + + >>> get_long_path_name('c:\\docume~1') + u'c:\\\\Documents and Settings' + + """ + try: + import ctypes + except ImportError: + raise ImportError('you need to have ctypes installed for this to work') + _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW + _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, + ctypes.c_uint ] + + buf = ctypes.create_unicode_buffer(260) + rv = _GetLongPathName(path, buf, 260) + if rv == 0 or rv > 260: + return path + else: + return buf.value diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index bba6d6a..22b7496 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -213,6 +213,13 @@ def make_runners(): if have_pexpect: top_mod.append('irunner.py') + if sys.platform == 'win32': + top_mod.append('platutils_win32.py') + elif os.name == 'posix': + top_mod.append('platutils_posix.py') + else: + top_mod.append('platutils_dummy.py') + # These are tested by nose, so skip IPython.kernel top_pack = ['config','Extensions','frontend', 'testing','tests','tools','UserConfig'] diff --git a/IPython/tests/test_magic.py b/IPython/tests/test_magic.py index 6815879..e090ea2 100644 --- a/IPython/tests/test_magic.py +++ b/IPython/tests/test_magic.py @@ -10,7 +10,7 @@ import types import nose.tools as nt -from IPython.platutils import find_cmd +from IPython.platutils import find_cmd, get_long_path_name from IPython.testing import decorators as dec from IPython.testing import tools as tt @@ -206,14 +206,16 @@ class TestMagicRun(object): self.tmpfile = f def run_tmpfile(self): + # This fails on Windows if self.tmpfile.name has spaces or "~" in it. + # See below and ticket https://bugs.launchpad.net/bugs/366353 _ip.magic('run %s' % self.tmpfile.name) # See https://bugs.launchpad.net/bugs/366353 @dec.skip_if_not_win32 def test_run_tempfile_path(self): - # self.run_tmpfile() # This is what triggers the error! tt.assert_equals(True,False,"%run doesn't work with tempfile paths on win32.") + # See https://bugs.launchpad.net/bugs/366353 @dec.skip_win32 def test_builtins_id(self): """Check that %run doesn't damage __builtins__ """ @@ -224,6 +226,7 @@ class TestMagicRun(object): bid2 = id(_ip.user_ns['__builtins__']) tt.assert_equals(bid1, bid2) + # See https://bugs.launchpad.net/bugs/366353 @dec.skip_win32 def test_builtins_type(self): """Check that the type of __builtins__ doesn't change with %run. @@ -235,6 +238,7 @@ class TestMagicRun(object): self.run_tmpfile() tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys)) + # See https://bugs.launchpad.net/bugs/366353 @dec.skip_win32 def test_prompts(self): """Test that prompts correctly generate after %run""" diff --git a/IPython/tests/test_platutils.py b/IPython/tests/test_platutils.py index ca2989e..36d189f 100644 --- a/IPython/tests/test_platutils.py +++ b/IPython/tests/test_platutils.py @@ -20,7 +20,7 @@ import sys import nose.tools as nt -from IPython.platutils import find_cmd, FindCmdError +from IPython.platutils import find_cmd, FindCmdError, get_long_path_name from IPython.testing import decorators as dec #----------------------------------------------------------------------------- @@ -46,3 +46,14 @@ def test_find_cmd(): def test_find_cmd_fail(): """Make sure that FindCmdError is raised if we can't find the cmd.""" nt.assert_raises(FindCmdError,find_cmd,'asdfasdf') + +@dec.skip_if_not_win32 +def test_get_long_path_name_win32(): + p = get_long_path_name('c:\\docume~1') + nt.assert_equals(p,u'c:\\Documents and Settings') + +@dec.skip_win32 +def test_get_long_path_name(): + p = get_long_path_name('/usr/local') + nt.assert_equals(p,'/usr/local') +