Permalink
Browse files

Merge pull request #734 from rkern/fix-windows-quotes

Allow %magic argument filenames with spaces to be specified with quotes under win32
  • Loading branch information...
2 parents 3048c01 + e3bec84 commit 6ecc466f4571913479172d974a6dd8bea5658941 @jdmarch jdmarch committed Aug 29, 2011
Showing with 89 additions and 15 deletions.
  1. +10 −6 IPython/core/magic.py
  2. +3 −3 IPython/testing/globalipapp.py
  3. +13 −1 IPython/testing/tools.py
  4. +21 −2 IPython/utils/path.py
  5. +42 −3 IPython/utils/tests/test_path.py
View
@@ -53,7 +53,7 @@
from IPython.lib.pylabtools import mpl_runner
from IPython.testing.skipdoctest import skip_doctest
from IPython.utils.io import file_read, nlprint
-from IPython.utils.path import get_py_filename
+from IPython.utils.path import get_py_filename, unquote_filename
from IPython.utils.process import arg_split, abbrev_cwd
from IPython.utils.terminal import set_term_title
from IPython.utils.text import LSString, SList, format_screen
@@ -1426,10 +1426,12 @@ def magic_prun(self, parameter_s ='',user_mode=1,
dump_file = opts.D[0]
text_file = opts.T[0]
if dump_file:
+ dump_file = unquote_filename(dump_file)
prof.dump_stats(dump_file)
print '\n*** Profile stats marshalled to file',\
`dump_file`+'.',sys_exit
if text_file:
+ text_file = unquote_filename(text_file)
pfile = file(text_file,'w')
pfile.write(output)
pfile.close()
@@ -2071,7 +2073,7 @@ def magic_save(self,parameter_s = ''):
it asks for confirmation before overwriting existing files."""
opts,args = self.parse_options(parameter_s,'r',mode='list')
- fname, codefrom = args[0], " ".join(args[1:])
+ fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
if not fname.endswith('.py'):
fname += '.py'
if os.path.isfile(fname):
@@ -2111,6 +2113,7 @@ def magic_loadpy(self, arg_s):
%loadpy myscript.py
%loadpy http://www.example.com/myscript.py
"""
+ arg_s = unquote_filename(arg_s)
if not arg_s.endswith('.py'):
raise ValueError('%%load only works with .py files: %s' % arg_s)
if arg_s.startswith('http'):
@@ -2127,12 +2130,13 @@ def _find_edit_target(self, args, opts, last_call):
def make_filename(arg):
"Make a filename from the given args"
+ arg = unquote_filename(arg)
try:
filename = get_py_filename(arg)
except IOError:
# If it ends with .py but doesn't already exist, assume we want
# a new file.
- if args.endswith('.py'):
+ if arg.endswith('.py'):
filename = arg
else:
filename = None
@@ -2826,8 +2830,7 @@ def magic_cd(self, parameter_s=''):
"Use '%%bookmark -l' to see your bookmarks." % ps)
# strip extra quotes on Windows, because os.chdir doesn't like them
- if sys.platform == 'win32':
- ps = ps.strip('\'"')
+ ps = unquote_filename(ps)
# at this point ps should point to the target dir
if ps:
try:
@@ -2870,7 +2873,7 @@ def magic_pushd(self, parameter_s=''):
"""
dir_s = self.shell.dir_stack
- tgt = os.path.expanduser(parameter_s)
+ tgt = os.path.expanduser(unquote_filename(parameter_s))
cwd = os.getcwdu().replace(self.home_dir,'~')
if tgt:
self.magic_cd(parameter_s)
@@ -3531,6 +3534,7 @@ def magic_notebook(self, s):
args = magic_arguments.parse_argstring(self.magic_notebook, s)
from IPython.nbformat import current
+ args.filename = unquote_filename(args.filename)
if args.export:
fname, name, format = current.parse_filename(args.filename)
cells = []
@@ -63,14 +63,14 @@ class py_file_finder(object):
def __init__(self,test_filename):
self.test_filename = test_filename
- def __call__(self,name):
+ def __call__(self,name,win32=False):
from IPython.utils.path import get_py_filename
try:
- return get_py_filename(name)
+ return get_py_filename(name,win32=win32)
except IOError:
test_dir = os.path.dirname(self.test_filename)
new_path = os.path.join(test_dir,name)
- return get_py_filename(new_path)
+ return get_py_filename(new_path,win32=win32)
def _run_ns_sync(self,arg_s,runner=None):
View
@@ -330,4 +330,16 @@ def mute_warn():
try:
yield
finally:
- warn.warn = save_warn
+ warn.warn = save_warn
+
+@contextmanager
+def make_tempfile(name):
+ """ Create an empty, named, temporary file for the duration of the context.
+ """
+ f = open(name, 'w')
+ f.close()
+ try:
+ yield
+ finally:
+ os.unlink(name)
+
View
@@ -82,13 +82,32 @@ def get_long_path_name(path):
return _get_long_path_name(path)
-def get_py_filename(name):
+def unquote_filename(name, win32=(sys.platform=='win32')):
+ """ On Windows, remove leading and trailing quotes from filenames.
+ """
+ if win32:
+ if name.startswith(("'", '"')) and name.endswith(("'", '"')):
+ name = name[1:-1]
+ return name
+
+
+def get_py_filename(name, force_win32=None):
"""Return a valid python filename in the current directory.
If the given name is not a file, it adds '.py' and searches again.
- Raises IOError with an informative message if the file isn't found."""
+ Raises IOError with an informative message if the file isn't found.
+
+ On Windows, apply Windows semantics to the filename. In particular, remove
+ any quoting that has been applied to it. This option can be forced for
+ testing purposes.
+ """
name = os.path.expanduser(name)
+ if force_win32 is None:
+ win32 = (sys.platform == 'win32')
+ else:
+ win32 = force_win32
+ name = unquote_filename(name, win32=win32)
if not os.path.isfile(name) and not name.endswith('.py'):
name += '.py'
if os.path.isfile(name):
@@ -12,6 +12,8 @@
# Imports
#-----------------------------------------------------------------------------
+from __future__ import with_statement
+
import os
import shutil
import sys
@@ -27,6 +29,7 @@
import IPython
from IPython.testing import decorators as dec
from IPython.testing.decorators import skip_if_not_win32, skip_win32
+from IPython.testing.tools import make_tempfile
from IPython.utils import path, io
# Platform-dependent imports
@@ -83,7 +86,7 @@ def setup_environment():
each testfunction needs a pristine environment.
"""
global oldstuff, platformstuff
- oldstuff = (env.copy(), os.name, path.get_home_dir, IPython.__file__)
+ oldstuff = (env.copy(), os.name, path.get_home_dir, IPython.__file__, os.getcwd())
if os.name == 'nt':
platformstuff = (wreg.OpenKey, wreg.QueryValueEx,)
@@ -92,7 +95,8 @@ def setup_environment():
def teardown_environment():
"""Restore things that were remebered by the setup_environment function
"""
- (oldenv, os.name, path.get_home_dir, IPython.__file__,) = oldstuff
+ (oldenv, os.name, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
+ os.chdir(old_wd)
reload(path)
for key in env.keys():
@@ -401,4 +405,39 @@ def test_not_writable_ipdir():
io.stderr = stderr
nt.assert_true('WARNING' in pipe.getvalue())
env.pop('IPYTHON_DIR', None)
-
+
+def test_unquote_filename():
+ for win32 in (True, False):
+ nt.assert_equals(path.unquote_filename('foo.py', win32=win32), 'foo.py')
+ nt.assert_equals(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py')
+ nt.assert_equals(path.unquote_filename('"foo.py"', win32=True), 'foo.py')
+ nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py')
+ nt.assert_equals(path.unquote_filename("'foo.py'", win32=True), 'foo.py')
+ nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py')
+ nt.assert_equals(path.unquote_filename('"foo.py"', win32=False), '"foo.py"')
+ nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"')
+ nt.assert_equals(path.unquote_filename("'foo.py'", win32=False), "'foo.py'")
+ nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'")
+
+@with_environment
+def test_get_py_filename():
+ os.chdir(TMP_TEST_DIR)
+ for win32 in (True, False):
+ with make_tempfile('foo.py'):
+ nt.assert_equals(path.get_py_filename('foo.py', force_win32=win32), 'foo.py')
+ nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo.py')
+ with make_tempfile('foo'):
+ nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo')
+ nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
+ nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32)
+ nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
+ true_fn = 'foo with spaces.py'
+ with make_tempfile(true_fn):
+ nt.assert_equals(path.get_py_filename('foo with spaces', force_win32=win32), true_fn)
+ nt.assert_equals(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn)
+ if win32:
+ nt.assert_equals(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn)
+ nt.assert_equals(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn)
+ else:
+ nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False)
+ nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False)

0 comments on commit 6ecc466

Please sign in to comment.