Skip to content
This repository

Fix paste/cpaste bug and refactor/cleanup that code a lot. #1007

Merged
merged 3 commits into from over 2 years ago

3 participants

Fernando Perez Min RK Stefan van der Walt
Fernando Perez
Owner

In fixing a pasting bug (mishandling of whitespace when input had
prompts) it became clear the pasting code hadn't been updated
when the new prefiltering machinery was added. Furthermore, the
pasting magics are only for the terminal, but the code was in the
base classes.

This refactors and simplifies the pasting code, moving it to the
terminal shell only, and removing unnecessary methods from the
main class (using small utility functions instead).

The tests were simplified because the previous regexp supported some
odd edge cases that are not valid in the normal prefiltering code. We
want to have a single location and set of rules for input
prefiltering, so I changed some of the test cases to be consistent
with what prefilter allows.

Fernando Perez
Owner

@stefanv, could you have a quick look and see if this fixes correctly the cases you'd seen?

Min RK
Owner

This is looking pretty good to me. One general question - store_or_execute() and rerun_pasted() are functions whose first argument is always the object that calls them, making them perfectly identical to instance methods in terms of implementation. What benefit does this approach have over them just being methods?

In this way, every single method of an object could be made a function. For future reference, which ones should be functions, and which should be methods?

Fernando Perez
Owner

They were actually methods, and you are totally correct that by this token we could completely strip the object down :) I don't have a hard rule yet and I'm just feeling my way through this, but it seems to me that our main interactive shell objects have become gigantic and unwieldy, so I was trying to reduce their method footprint and API a little bit.

Since these were little pieces of functionality only used by the terminal application, it seemed like a cleaner solution to just refactor them out into separate standalone functions. That would also make it much easier to test them in isolation with mock objects that only provide one or two methods, something harder to do when they are methods of the main thing.

I'm not trying to go and rip out everything from the main shell object, but these didn't really feel like 'core' functionality (in fact they were _private in the previous implementation). So it's really mostly an instinct design call, and one that I'd love feedback on. Do you agree in general with trying to (when reasonably easy and non-disruptive as was the case here) simplify a little bit the official public API of our big Shell object, and with this approach? I mostly want us to find a good design balance for this that will make the overall use and maintenance of the code easier...

Stefan van der Walt

E-mail pasting no longer works, e.g.

>> def foo(x):
>>     return x

Also, some valid Python causes confusion:

>>> def foo(x): return 1 \
...     > 1
Min RK
Owner

@fperez - I agree that we should move in a direction of more functions and fewer methods, but these seem like they really are methods, since copying/pasting them into the Class scope would require no internal changes at all (aside from changing invocation back from f(self to self.f(). They are still highly stateful, depending on and affecting the active state of the shell instance and various members. I'm not sure that anything that calls shell.run_cell() is better off being split off into a function.

I don't feel strongly and I don't know where the line should be drawn, but my first inclination is that if you have to provide the shell instance itself, rather than some of its members, it's probably a method.

Fernando Perez
Owner

Just rebased to sort out a conflict and force-pushed. Too tired now to work any more on this, will get back to it in a couple of days.

added some commits November 16, 2011
Fernando Perez Fix paste/cpaste bug and refactor/cleanup that code a lot.
In fixing a pasting bug (mishandling of whitespace when input had
prompts) it became clear the pasting code hadn't been updated
when the new prefiltering machinery was added.  Furthermore, the
pasting magics are only for the terminal, but the code was in the
base classes.

This refactors and simplifies the pasting code, moving it to the
terminal shell only, and removing unnecessary methods from the
main class (using small utility functions instead).

The tests were simplified because the previous regexp supported some
odd edge cases that are not valid in the normal prefiltering code.  We
want to have a single location and set of rules for input
prefiltering, so I changed some of the test cases to be consistent
with what prefilter allows.
8bb887c
Fernando Perez Move tests for magics that are terminal-specific to their own file. 8259953
Fernando Perez Add tests for email quote stripping.
Also, clarify why certain utilities are kept as standalone functions
instead of making them methods.
84830ec
Fernando Perez
Owner

@stefanv, I fixed the email case and added some tests for that kind of format, let me know if this looks OK now.

@minrk, here's how I view the ones in this particular case: while I agree with you that those are basically methods in all but name right now, I hope that soon we'll be able to refactor our magic system into standalone objects. And in this case, those methods are really utilities of the paste/cpaste magics, not of the shell itself. If those magics were in a separate object (say one added by a user in an extension), they would never modify the shell as methods, they'd simply pass it as an argument. So I think that leaving them as standalone functions now is the right thing to do, in anticipation for an eventual refactoring into a new object, a Magic, that would put them together with paste/cpaste.

If you guys agree with this, I'll go ahead and merge. Thanks for the review!

Min RK
Owner

@fperez - I think this is fine. It does seem a bit odd to pull methods out into functions, with the ultimate goal that they become methods of a different object in the future. I do appreciate the desire to pull things off of the Shell, so it makes sense.

If @stefanv's says his cases work, go for it.

Fernando Perez
Owner

Thanks, @minrk. I did add a comment around them to try and clarify the intent of the somewhat odd refactoring. I hope to find the time soon to draft my ideas on the magics and post them on the dev list for feedback.

@stefanv, note that I fixed email pasting, but not that very odd corner case you found. The logic for handling continuation lines gets pretty complicated if we want to mix in automatic removal of special characters, so I think it's OK if the pasting utilities don't cover them. I don't want them to become overly complex. As long as we handle that code in the normal input prompt, I think that's an acceptable compromise. What do you think?

Stefan van der Walt

@fperez Thanks, the e-mail case is the most common one I deal with. Dealing with all the corner cases cleanly may be very hard, so I'm be happy with the current behaviour.

Fernando Perez
Owner

Great, merging and closing. Thanks for the feedback!

Fernando Perez fperez merged commit 780b7c5 into from November 26, 2011
Fernando Perez fperez closed this November 26, 2011
Fernando Perez fperez referenced this pull request from a commit January 10, 2012
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 3 unique commits by 1 author.

Nov 25, 2011
Fernando Perez Fix paste/cpaste bug and refactor/cleanup that code a lot.
In fixing a pasting bug (mishandling of whitespace when input had
prompts) it became clear the pasting code hadn't been updated
when the new prefiltering machinery was added.  Furthermore, the
pasting magics are only for the terminal, but the code was in the
base classes.

This refactors and simplifies the pasting code, moving it to the
terminal shell only, and removing unnecessary methods from the
main class (using small utility functions instead).

The tests were simplified because the previous regexp supported some
odd edge cases that are not valid in the normal prefiltering code.  We
want to have a single location and set of rules for input
prefiltering, so I changed some of the test cases to be consistent
with what prefilter allows.
8bb887c
Fernando Perez Move tests for magics that are terminal-specific to their own file. 8259953
Fernando Perez Add tests for email quote stripping.
Also, clarify why certain utilities are kept as standalone functions
instead of making them methods.
84830ec
This page is out of date. Refresh to see the latest.
60  IPython/core/magic.py
@@ -25,7 +25,6 @@
25 25
 import shutil
26 26
 import re
27 27
 import time
28  
-import textwrap
29 28
 from StringIO import StringIO
30 29
 from getopt import getopt,GetoptError
31 30
 from pprint import pformat
@@ -3203,65 +3202,6 @@ def magic_pycat(self, parameter_s=''):
3203 3202
 
3204 3203
         page.page(self.shell.pycolorize(cont))
3205 3204
 
3206  
-    def _rerun_pasted(self):
3207  
-        """ Rerun a previously pasted command.
3208  
-        """
3209  
-        b = self.user_ns.get('pasted_block', None)
3210  
-        if b is None:
3211  
-            raise UsageError('No previous pasted block available')
3212  
-        print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))
3213  
-        exec b in self.user_ns
3214  
-
3215  
-    def _get_pasted_lines(self, sentinel):
3216  
-        """ Yield pasted lines until the user enters the given sentinel value.
3217  
-        """
3218  
-        from IPython.core import interactiveshell
3219  
-        print "Pasting code; enter '%s' alone on the line to stop." % sentinel
3220  
-        while True:
3221  
-            try:
3222  
-                l = self.shell.raw_input_original(':')
3223  
-                if l == sentinel:
3224  
-                    return
3225  
-                else:
3226  
-                    yield l
3227  
-            except EOFError:
3228  
-                print '<EOF>'
3229  
-                return
3230  
-
3231  
-    def _strip_pasted_lines_for_code(self, raw_lines):
3232  
-        """ Strip non-code parts of a sequence of lines to return a block of
3233  
-        code.
3234  
-        """
3235  
-        # Regular expressions that declare text we strip from the input:
3236  
-        strip_re =  [r'^\s*In \[\d+\]:', # IPython input prompt
3237  
-                     r'^\s*(\s?>)+', # Python input prompt
3238  
-                     r'^\s*\.{3,}', # Continuation prompts
3239  
-                     r'^\++',
3240  
-                     ]
3241  
-
3242  
-        strip_from_start = map(re.compile,strip_re)
3243  
-
3244  
-        lines = []
3245  
-        for l in raw_lines:
3246  
-            for pat in strip_from_start:
3247  
-                l = pat.sub('',l)
3248  
-            lines.append(l)
3249  
-
3250  
-        block = "\n".join(lines) + '\n'
3251  
-        #print "block:\n",block
3252  
-        return block
3253  
-
3254  
-    def _execute_block(self, block, par):
3255  
-        """ Execute a block, or store it in a variable, per the user's request.
3256  
-        """
3257  
-        if not par:
3258  
-            b = textwrap.dedent(block)
3259  
-            self.user_ns['pasted_block'] = b
3260  
-            self.run_cell(b)
3261  
-        else:
3262  
-            self.user_ns[par] = SList(block.splitlines())
3263  
-            print "Block assigned to '%s'" % par
3264  
-
3265 3205
     def magic_quickref(self,arg):
3266 3206
         """ Show a quick reference sheet """
3267 3207
         import IPython.core.usage
122  IPython/core/tests/test_magic.py
@@ -9,14 +9,9 @@
9 9
 #-----------------------------------------------------------------------------
10 10
 
11 11
 import os
12  
-import sys
13  
-import tempfile
14  
-import types
15  
-from StringIO import StringIO
16 12
 
17 13
 import nose.tools as nt
18 14
 
19  
-from IPython.utils.path import get_long_path_name
20 15
 from IPython.testing import decorators as dec
21 16
 from IPython.testing import tools as tt
22 17
 from IPython.utils import py3compat
@@ -24,6 +19,7 @@
24 19
 #-----------------------------------------------------------------------------
25 20
 # Test functions begin
26 21
 #-----------------------------------------------------------------------------
  22
+
27 23
 def test_rehashx():
28 24
     # clear up everything
29 25
     _ip = get_ipython()
@@ -202,67 +198,6 @@ def test_numpy_clear_array_undec():
202 198
     yield (nt.assert_false, 'a' in _ip.user_ns)
203 199
     
204 200
 
205  
-# Multiple tests for clipboard pasting
206  
-@dec.parametric
207  
-def test_paste():
208  
-    _ip = get_ipython()
209  
-    def paste(txt, flags='-q'):
210  
-        """Paste input text, by default in quiet mode"""
211  
-        hooks.clipboard_get = lambda : txt
212  
-        _ip.magic('paste '+flags)
213  
-
214  
-    # Inject fake clipboard hook but save original so we can restore it later
215  
-    hooks = _ip.hooks
216  
-    user_ns = _ip.user_ns
217  
-    original_clip = hooks.clipboard_get
218  
-
219  
-    try:
220  
-        # Run tests with fake clipboard function
221  
-        user_ns.pop('x', None)
222  
-        paste('x=1')
223  
-        yield nt.assert_equal(user_ns['x'], 1)
224  
-
225  
-        user_ns.pop('x', None)
226  
-        paste('>>> x=2')
227  
-        yield nt.assert_equal(user_ns['x'], 2)
228  
-
229  
-        paste("""
230  
-        >>> x = [1,2,3]
231  
-        >>> y = []
232  
-        >>> for i in x:
233  
-        ...     y.append(i**2)
234  
-        ...
235  
-        """)
236  
-        yield nt.assert_equal(user_ns['x'], [1,2,3])
237  
-        yield nt.assert_equal(user_ns['y'], [1,4,9])
238  
-
239  
-        # Now, test that paste -r works
240  
-        user_ns.pop('x', None)
241  
-        yield nt.assert_false('x' in user_ns)
242  
-        _ip.magic('paste -r')
243  
-        yield nt.assert_equal(user_ns['x'], [1,2,3])
244  
-
245  
-        # Also test paste echoing, by temporarily faking the writer
246  
-        w = StringIO()
247  
-        writer = _ip.write
248  
-        _ip.write = w.write
249  
-        code = """
250  
-        a = 100
251  
-        b = 200"""
252  
-        try:
253  
-            paste(code,'')
254  
-            out = w.getvalue()
255  
-        finally:
256  
-            _ip.write = writer
257  
-        yield nt.assert_equal(user_ns['a'], 100)
258  
-        yield nt.assert_equal(user_ns['b'], 200)
259  
-        yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
260  
-        
261  
-    finally:
262  
-        # Restore original hook
263  
-        hooks.clipboard_get = original_clip
264  
-
265  
-
266 201
 def test_time():
267 202
     _ip.magic('time None')
268 203
 
@@ -317,61 +252,6 @@ def test_dirops():
317 252
         os.chdir(startdir)
318 253
 
319 254
 
320  
-def check_cpaste(code, should_fail=False):
321  
-    """Execute code via 'cpaste' and ensure it was executed, unless
322  
-    should_fail is set.
323  
-    """
324  
-    _ip.user_ns['code_ran'] = False
325  
-
326  
-    src = StringIO()
327  
-    if not hasattr(src, 'encoding'):
328  
-        # IPython expects stdin to have an encoding attribute
329  
-        src.encoding = None
330  
-    src.write('\n')
331  
-    src.write(code)
332  
-    src.write('\n--\n')
333  
-    src.seek(0)
334  
-
335  
-    stdin_save = sys.stdin
336  
-    sys.stdin = src
337  
-    
338  
-    try:
339  
-        context = tt.AssertPrints if should_fail else tt.AssertNotPrints
340  
-        with context("Traceback (most recent call last)"):
341  
-                _ip.magic('cpaste')
342  
-        
343  
-        if not should_fail:
344  
-            assert _ip.user_ns['code_ran']
345  
-    finally:
346  
-        sys.stdin = stdin_save
347  
-
348  
-
349  
-def test_cpaste():
350  
-    """Test cpaste magic"""
351  
-
352  
-    def run():
353  
-        """Marker function: sets a flag when executed.
354  
-        """
355  
-        _ip.user_ns['code_ran'] = True
356  
-        return 'run' # return string so '+ run()' doesn't result in success
357  
-
358  
-    tests = {'pass': ["> > > run()",
359  
-                      ">>> > run()",
360  
-                      "+++ run()",
361  
-                      "++ run()",
362  
-                      "  >>> run()"],
363  
-
364  
-             'fail': ["+ + run()",
365  
-                      " ++ run()"]}
366  
-
367  
-    _ip.user_ns['run'] = run
368  
-
369  
-    for code in tests['pass']:
370  
-        check_cpaste(code)
371  
-
372  
-    for code in tests['fail']:
373  
-        check_cpaste(code, should_fail=True)
374  
-
375 255
 def test_xmode():
376 256
     # Calling xmode three times should be a no-op
377 257
     xmode = _ip.InteractiveTB.mode
164  IPython/core/tests/test_magic_terminal.py
... ...
@@ -0,0 +1,164 @@
  1
+"""Tests for various magic functions specific to the terminal frontend.
  2
+
  3
+Needs to be run by nose (to make ipython session available).
  4
+"""
  5
+from __future__ import absolute_import
  6
+
  7
+#-----------------------------------------------------------------------------
  8
+# Imports
  9
+#-----------------------------------------------------------------------------
  10
+
  11
+import sys
  12
+from StringIO import StringIO
  13
+
  14
+import nose.tools as nt
  15
+
  16
+from IPython.testing import decorators as dec
  17
+from IPython.testing import tools as tt
  18
+
  19
+#-----------------------------------------------------------------------------
  20
+# Test functions begin
  21
+#-----------------------------------------------------------------------------
  22
+
  23
+def check_cpaste(code, should_fail=False):
  24
+    """Execute code via 'cpaste' and ensure it was executed, unless
  25
+    should_fail is set.
  26
+    """
  27
+    _ip.user_ns['code_ran'] = False
  28
+
  29
+    src = StringIO()
  30
+    if not hasattr(src, 'encoding'):
  31
+        # IPython expects stdin to have an encoding attribute
  32
+        src.encoding = None
  33
+    src.write('\n')
  34
+    src.write(code)
  35
+    src.write('\n--\n')
  36
+    src.seek(0)
  37
+
  38
+    stdin_save = sys.stdin
  39
+    sys.stdin = src
  40
+
  41
+    try:
  42
+        context = tt.AssertPrints if should_fail else tt.AssertNotPrints
  43
+        with context("Traceback (most recent call last)"):
  44
+                _ip.magic('cpaste')
  45
+
  46
+        if not should_fail:
  47
+            assert _ip.user_ns['code_ran']
  48
+    finally:
  49
+        sys.stdin = stdin_save
  50
+
  51
+
  52
+def test_cpaste():
  53
+    """Test cpaste magic"""
  54
+
  55
+    def run():
  56
+        """Marker function: sets a flag when executed.
  57
+        """
  58
+        _ip.user_ns['code_ran'] = True
  59
+        return 'run' # return string so '+ run()' doesn't result in success
  60
+
  61
+    tests = {'pass': ["run()",
  62
+                      "In [1]: run()",
  63
+                      "In [1]: if 1:\n   ...:     run()",
  64
+                      "> > > run()",
  65
+                      ">>> run()",
  66
+                      "   >>> run()",
  67
+                      ],
  68
+
  69
+             'fail': ["1 + run()",
  70
+                      "++ run()"]}
  71
+
  72
+    _ip.user_ns['run'] = run
  73
+
  74
+    for code in tests['pass']:
  75
+        check_cpaste(code)
  76
+
  77
+    for code in tests['fail']:
  78
+        check_cpaste(code, should_fail=True)
  79
+
  80
+
  81
+# Multiple tests for clipboard pasting
  82
+def test_paste():
  83
+    _ip = get_ipython()
  84
+
  85
+    def paste(txt, flags='-q'):
  86
+        """Paste input text, by default in quiet mode"""
  87
+        hooks.clipboard_get = lambda : txt
  88
+        _ip.magic('paste '+flags)
  89
+
  90
+    # Inject fake clipboard hook but save original so we can restore it later
  91
+    hooks = _ip.hooks
  92
+    user_ns = _ip.user_ns
  93
+    original_clip = hooks.clipboard_get
  94
+
  95
+    try:
  96
+        # Run tests with fake clipboard function
  97
+        user_ns.pop('x', None)
  98
+        paste('x=1')
  99
+        nt.assert_equal(user_ns['x'], 1)
  100
+
  101
+        user_ns.pop('x', None)
  102
+        paste('>>> x=2')
  103
+        nt.assert_equal(user_ns['x'], 2)
  104
+
  105
+        paste("""
  106
+        >>> x = [1,2,3]
  107
+        >>> y = []
  108
+        >>> for i in x:
  109
+        ...     y.append(i**2)
  110
+        ...
  111
+        """)
  112
+        nt.assert_equal(user_ns['x'], [1,2,3])
  113
+        nt.assert_equal(user_ns['y'], [1,4,9])
  114
+
  115
+        # Now, test that paste -r works
  116
+        user_ns.pop('x', None)
  117
+        nt.assert_false('x' in user_ns)
  118
+        _ip.magic('paste -r')
  119
+        nt.assert_equal(user_ns['x'], [1,2,3])
  120
+
  121
+        # Test pasting of email-quoted contents
  122
+        paste("""
  123
+        >> def foo(x):
  124
+        >>     return x + 1
  125
+        >> x = foo(1.1)
  126
+        """)
  127
+        nt.assert_equal(user_ns['x'], 2.1)
  128
+
  129
+        # Email again; some programs add a space also at each quoting level
  130
+        paste("""
  131
+        > > def foo(x):
  132
+        > >     return x + 1
  133
+        > > x = foo(2.1)
  134
+        """)
  135
+        nt.assert_equal(user_ns['x'], 3.1)
  136
+
  137
+        # Email quoting of interactive input
  138
+        paste("""
  139
+        >> >>> def f(x):
  140
+        >> ...   return x+1
  141
+        >> ...
  142
+        >> >>> x = f(2.5)
  143
+        """)
  144
+        nt.assert_equal(user_ns['x'], 3.5)
  145
+
  146
+        # Also test paste echoing, by temporarily faking the writer
  147
+        w = StringIO()
  148
+        writer = _ip.write
  149
+        _ip.write = w.write
  150
+        code = """
  151
+        a = 100
  152
+        b = 200"""
  153
+        try:
  154
+            paste(code,'')
  155
+            out = w.getvalue()
  156
+        finally:
  157
+            _ip.write = writer
  158
+        nt.assert_equal(user_ns['a'], 100)
  159
+        nt.assert_equal(user_ns['b'], 200)
  160
+        nt.assert_equal(out, code+"\n## -- End pasted text --\n")
  161
+
  162
+    finally:
  163
+        # Restore original hook
  164
+        hooks.clipboard_get = original_clip
109  IPython/frontend/terminal/interactiveshell.py
@@ -19,6 +19,7 @@
19 19
 import os
20 20
 import re
21 21
 import sys
  22
+import textwrap
22 23
 
23 24
 try:
24 25
     from contextlib import nested
@@ -35,7 +36,7 @@
35 36
 from IPython.utils.terminal import toggle_set_term_title, set_term_title
36 37
 from IPython.utils.process import abbrev_cwd
37 38
 from IPython.utils.warn import warn, error
38  
-from IPython.utils.text import num_ini_spaces
  39
+from IPython.utils.text import num_ini_spaces, SList
39 40
 from IPython.utils.traitlets import Integer, CBool, Unicode
40 41
 
41 42
 #-----------------------------------------------------------------------------
@@ -52,6 +53,73 @@ def get_default_editor():
52 53
             ed = 'notepad' # same in Windows!
53 54
     return ed
54 55
 
  56
+
  57
+def get_pasted_lines(sentinel, input=raw_input):
  58
+    """ Yield pasted lines until the user enters the given sentinel value.
  59
+    """
  60
+    print "Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
  61
+          % sentinel
  62
+    while True:
  63
+        try:
  64
+            l = input(':')
  65
+            if l == sentinel:
  66
+                return
  67
+            else:
  68
+                yield l
  69
+        except EOFError:
  70
+            print '<EOF>'
  71
+            return
  72
+
  73
+
  74
+def strip_email_quotes(raw_lines):
  75
+    """ Strip email quotation marks at the beginning of each line.
  76
+
  77
+    We don't do any more input transofrmations here because the main shell's
  78
+    prefiltering handles other cases.
  79
+    """
  80
+    lines = [re.sub(r'^\s*(\s?>)+', '', l) for l in raw_lines]
  81
+    return '\n'.join(lines) + '\n'
  82
+
  83
+
  84
+# These two functions are needed by the %paste/%cpaste magics.  In practice
  85
+# they are basically methods (they take the shell as their first argument), but
  86
+# we leave them as standalone functions because eventually the magics
  87
+# themselves will become separate objects altogether.  At that point, the
  88
+# magics will have access to the shell object, and these functions can be made
  89
+# methods of the magic object, but not of the shell.
  90
+
  91
+def store_or_execute(shell, block, name):
  92
+    """ Execute a block, or store it in a variable, per the user's request.
  93
+    """
  94
+    # Dedent and prefilter so what we store matches what is executed by
  95
+    # run_cell.
  96
+    b = shell.prefilter(textwrap.dedent(block))
  97
+
  98
+    if name:
  99
+        # If storing it for further editing, run the prefilter on it
  100
+        shell.user_ns[name] = SList(b.splitlines())
  101
+        print "Block assigned to '%s'" % name
  102
+    else:
  103
+        shell.user_ns['pasted_block'] = b
  104
+        shell.run_cell(b)
  105
+
  106
+
  107
+def rerun_pasted(shell, name='pasted_block'):
  108
+    """ Rerun a previously pasted command.
  109
+    """
  110
+    b = shell.user_ns.get(name)
  111
+
  112
+    # Sanity checks
  113
+    if b is None:
  114
+        raise UsageError('No previous pasted block available')
  115
+    if not isinstance(b, basestring):
  116
+        raise UsageError(
  117
+            "Variable 'pasted_block' is not a string, can't execute")
  118
+
  119
+    print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))
  120
+    shell.run_cell(b)
  121
+
  122
+
55 123
 #-----------------------------------------------------------------------------
56 124
 # Main class
57 125
 #-----------------------------------------------------------------------------
@@ -523,9 +591,9 @@ def magic_autoindent(self, parameter_s = ''):
523 591
     def magic_cpaste(self, parameter_s=''):
524 592
         """Paste & execute a pre-formatted code block from clipboard.
525 593
 
526  
-        You must terminate the block with '--' (two minus-signs) or Ctrl-D alone on the
527  
-        line. You can also provide your own sentinel with '%paste -s %%' ('%%'
528  
-        is the new sentinel for this operation)
  594
+        You must terminate the block with '--' (two minus-signs) or Ctrl-D
  595
+        alone on the line. You can also provide your own sentinel with '%paste
  596
+        -s %%' ('%%' is the new sentinel for this operation)
529 597
 
530 598
         The block is dedented prior to execution to enable execution of method
531 599
         definitions. '>' and '+' characters at the beginning of a line are
@@ -562,18 +630,14 @@ def magic_cpaste(self, parameter_s=''):
562 630
           Hello world!
563 631
         """
564 632
 
565  
-        opts,args = self.parse_options(parameter_s,'rs:',mode='string')
566  
-        par = args.strip()
567  
-        if opts.has_key('r'):
568  
-            self._rerun_pasted()
  633
+        opts, name = self.parse_options(parameter_s, 'rs:', mode='string')
  634
+        if 'r' in opts:
  635
+            rerun_pasted(self.shell)
569 636
             return
570 637
 
571  
-        sentinel = opts.get('s','--')
572  
-
573  
-        block = self._strip_pasted_lines_for_code(
574  
-            self._get_pasted_lines(sentinel))
575  
-
576  
-        self._execute_block(block, par)
  638
+        sentinel = opts.get('s', '--')
  639
+        block = strip_email_quotes(get_pasted_lines(sentinel))
  640
+        store_or_execute(self.shell, block, name)
577 641
 
578 642
     def magic_paste(self, parameter_s=''):
579 643
         """Paste & execute a pre-formatted code block from clipboard.
@@ -606,14 +670,13 @@ def magic_paste(self, parameter_s=''):
606 670
         --------
607 671
         cpaste: manually paste code into terminal until you mark its end.
608 672
         """
609  
-        opts,args = self.parse_options(parameter_s,'rq',mode='string')
610  
-        par = args.strip()
611  
-        if opts.has_key('r'):
612  
-            self._rerun_pasted()
  673
+        opts, name = self.parse_options(parameter_s, 'rq', mode='string')
  674
+        if 'r' in opts:
  675
+            rerun_pasted(self.shell)
613 676
             return
614 677
         try:
615 678
             text = self.shell.hooks.clipboard_get()
616  
-            block = self._strip_pasted_lines_for_code(text.splitlines())
  679
+            block = strip_email_quotes(text.splitlines())
617 680
         except TryNext as clipboard_exc:
618 681
             message = getattr(clipboard_exc, 'args')
619 682
             if message:
@@ -623,15 +686,16 @@ def magic_paste(self, parameter_s=''):
623 686
             return
624 687
 
625 688
         # By default, echo back to terminal unless quiet mode is requested
626  
-        if not opts.has_key('q'):
  689
+        if 'q' not in opts:
627 690
             write = self.shell.write
628 691
             write(self.shell.pycolorize(block))
629 692
             if not block.endswith('\n'):
630 693
                 write('\n')
631 694
             write("## -- End pasted text --\n")
632 695
 
633  
-        self._execute_block(block, par)
  696
+        store_or_execute(self.shell, block, name)
634 697
 
  698
+    # Class-level: add a '%cls' magic only on Windows
635 699
     if sys.platform == 'win32':
636 700
         def magic_cls(self, s):
637 701
             """Clear screen.
@@ -640,7 +704,8 @@ def magic_cls(self, s):
640 704
 
641 705
     def showindentationerror(self):
642 706
         super(TerminalInteractiveShell, self).showindentationerror()
643  
-        print("If you want to paste code into IPython, try the %paste magic function.")
  707
+        print("If you want to paste code into IPython, try the "
  708
+              "%paste and %cpaste magic functions.")
644 709
 
645 710
 
646 711
 InteractiveShellABC.register(TerminalInteractiveShell)
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.