Skip to content

Commit

Permalink
Merge pull request #2015 from fperez/paste_1258
Browse files Browse the repository at this point in the history
Fixes for %paste with special transformations.

Fix the fact that we use prefilter too aggressively in `%paste`, which results in applying single-line transformations inside of strings and function definitions.

Closes #1258.
  • Loading branch information
fperez committed Jun 28, 2012
2 parents bb4488a + 85e9d88 commit 11b77df
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 129 deletions.
182 changes: 108 additions & 74 deletions IPython/core/tests/test_magic_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@

import sys
from StringIO import StringIO
from unittest import TestCase

import nose.tools as nt

from IPython.testing import tools as tt

#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
ip = get_ipython()

#-----------------------------------------------------------------------------
# Test functions begin
#-----------------------------------------------------------------------------
Expand All @@ -23,13 +29,12 @@ def check_cpaste(code, should_fail=False):
"""Execute code via 'cpaste' and ensure it was executed, unless
should_fail is set.
"""
_ip.user_ns['code_ran'] = False
ip.user_ns['code_ran'] = False

src = StringIO()
if not hasattr(src, 'encoding'):
# IPython expects stdin to have an encoding attribute
src.encoding = None
src.write('\n')
src.write(code)
src.write('\n--\n')
src.seek(0)
Expand All @@ -40,10 +45,10 @@ def check_cpaste(code, should_fail=False):
try:
context = tt.AssertPrints if should_fail else tt.AssertNotPrints
with context("Traceback (most recent call last)"):
_ip.magic('cpaste')
ip.magic('cpaste')

if not should_fail:
assert _ip.user_ns['code_ran']
assert ip.user_ns['code_ran']
finally:
sys.stdin = stdin_save

Expand All @@ -52,30 +57,30 @@ def check_cpaste(code, should_fail=False):
def test_cpaste():
"""Test cpaste magic"""

def run():
def runf():
"""Marker function: sets a flag when executed.
"""
_ip.user_ns['code_ran'] = True
return 'run' # return string so '+ run()' doesn't result in success

tests = {'pass': ["run()",
"In [1]: run()",
"In [1]: if 1:\n ...: run()",
"> > > run()",
">>> run()",
" >>> run()",
ip.user_ns['code_ran'] = True
return 'runf' # return string so '+ runf()' doesn't result in success

tests = {'pass': ["runf()",
"In [1]: runf()",
"In [1]: if 1:\n ...: runf()",
"> > > runf()",
">>> runf()",
" >>> runf()",
],

'fail': ["1 + run()",
'fail': ["1 + runf()",
]}

# I don't know why this is failing specifically on Python 3.1. I've
# checked it manually interactively, but we don't care enough about 3.1
# to spend time fiddling with the tests, so we just skip it.
if not PY31:
tests['fail'].append("++ run()")
tests['fail'].append("++ runf()")

_ip.user_ns['run'] = run
ip.user_ns['runf'] = runf

for code in tests['pass']:
check_cpaste(code)
Expand All @@ -84,87 +89,116 @@ def run():
check_cpaste(code, should_fail=True)


# Multiple tests for clipboard pasting
def test_paste():
_ip = get_ipython()
class PasteTestCase(TestCase):
"""Multiple tests for clipboard pasting"""

def paste(txt, flags='-q'):
def paste(self, txt, flags='-q'):
"""Paste input text, by default in quiet mode"""
hooks.clipboard_get = lambda : txt
_ip.magic('paste '+flags)
ip.hooks.clipboard_get = lambda : txt
ip.magic('paste '+flags)

# Inject fake clipboard hook but save original so we can restore it later
hooks = _ip.hooks
user_ns = _ip.user_ns
original_clip = hooks.clipboard_get
def setUp(self):
# Inject fake clipboard hook but save original so we can restore it later
self.original_clip = ip.hooks.clipboard_get

try:
# Run tests with fake clipboard function
user_ns.pop('x', None)
paste('x=1')
nt.assert_equal(user_ns['x'], 1)

user_ns.pop('x', None)
paste('>>> x=2')
nt.assert_equal(user_ns['x'], 2)

paste("""
def tearDown(self):
# Restore original hook
ip.hooks.clipboard_get = self.original_clip

def test_paste(self):
ip.user_ns.pop('x', None)
self.paste('x = 1')
nt.assert_equal(ip.user_ns['x'], 1)
ip.user_ns.pop('x')

def test_paste_pyprompt(self):
ip.user_ns.pop('x', None)
self.paste('>>> x=2')
nt.assert_equal(ip.user_ns['x'], 2)
ip.user_ns.pop('x')

def test_paste_py_multi(self):
self.paste("""
>>> x = [1,2,3]
>>> y = []
>>> for i in x:
... y.append(i**2)
...
...
""")
nt.assert_equal(user_ns['x'], [1,2,3])
nt.assert_equal(user_ns['y'], [1,4,9])

# Now, test that paste -r works
user_ns.pop('x', None)
nt.assert_false('x' in user_ns)
_ip.magic('paste -r')
nt.assert_equal(user_ns['x'], [1,2,3])

# Test pasting of email-quoted contents
paste("""
nt.assert_equal(ip.user_ns['x'], [1,2,3])
nt.assert_equal(ip.user_ns['y'], [1,4,9])

def test_paste_py_multi_r(self):
"Now, test that self.paste -r works"
nt.assert_equal(ip.user_ns.pop('x'), [1,2,3])
nt.assert_equal(ip.user_ns.pop('y'), [1,4,9])
nt.assert_false('x' in ip.user_ns)
ip.magic('paste -r')
nt.assert_equal(ip.user_ns['x'], [1,2,3])
nt.assert_equal(ip.user_ns['y'], [1,4,9])

def test_paste_email(self):
"Test pasting of email-quoted contents"
self.paste("""\
>> def foo(x):
>> return x + 1
>> x = foo(1.1)
""")
nt.assert_equal(user_ns['x'], 2.1)
>> xx = foo(1.1)""")
nt.assert_equal(ip.user_ns['xx'], 2.1)

# Email again; some programs add a space also at each quoting level
paste("""
def test_paste_email2(self):
"Email again; some programs add a space also at each quoting level"
self.paste("""\
> > def foo(x):
> > return x + 1
> > x = foo(2.1)
""")
nt.assert_equal(user_ns['x'], 3.1)
> > yy = foo(2.1) """)
nt.assert_equal(ip.user_ns['yy'], 3.1)

# Email quoting of interactive input
paste("""
def test_paste_email_py(self):
"Email quoting of interactive input"
self.paste("""\
>> >>> def f(x):
>> ... return x+1
>> ...
>> >>> x = f(2.5)
""")
nt.assert_equal(user_ns['x'], 3.5)
>> ...
>> >>> zz = f(2.5) """)
nt.assert_equal(ip.user_ns['zz'], 3.5)

# Also test paste echoing, by temporarily faking the writer
def test_paste_echo(self):
"Also test self.paste echoing, by temporarily faking the writer"
w = StringIO()
writer = _ip.write
_ip.write = w.write
writer = ip.write
ip.write = w.write
code = """
a = 100
b = 200"""
try:
paste(code,'')
self.paste(code,'')
out = w.getvalue()
finally:
_ip.write = writer
nt.assert_equal(user_ns['a'], 100)
nt.assert_equal(user_ns['b'], 200)
ip.write = writer
nt.assert_equal(ip.user_ns['a'], 100)
nt.assert_equal(ip.user_ns['b'], 200)
nt.assert_equal(out, code+"\n## -- End pasted text --\n")

finally:
# Restore original hook
hooks.clipboard_get = original_clip
def test_paste_leading_commas(self):
"Test multiline strings with leading commas"
tm = ip.magics_manager.registry['TerminalMagics']
s = '''\
a = """
,1,2,3
"""'''
ip.user_ns.pop('foo', None)
tm.store_or_execute(s, 'foo')
nt.assert_in('foo', ip.user_ns)


def test_paste_trailing_question(self):
"Test pasting sources with trailing question marks"
tm = ip.magics_manager.registry['TerminalMagics']
s = '''\
def funcfoo():
if True: #am i true?
return 'fooresult'
'''
ip.user_ns.pop('funcfoo', None)
self.paste(s)
nt.assert_equals(ip.user_ns['funcfoo'](), 'fooresult')

0 comments on commit 11b77df

Please sign in to comment.