##// END OF EJS Templates
Merging -r 1181 from lp:ipython....
Brian Granger -
r2128:edd2e623 merge
parent child Browse files
Show More
@@ -0,0 +1,56 b''
1 """ Utilities for accessing the platform's clipboard.
2 """
3
4 import subprocess
5 import sys
6
7 from IPython.ipapi import TryNext
8
9
10 def win32_clipboard_get():
11 """ Get the current clipboard's text on Windows.
12
13 Requires Mark Hammond's pywin32 extensions.
14 """
15 try:
16 import win32clipboard
17 except ImportError:
18 message = ("Getting text from the clipboard requires the pywin32 "
19 "extensions: http://sourceforge.net/projects/pywin32/")
20 raise TryNext(message)
21 win32clipboard.OpenClipboard()
22 text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
23 # FIXME: convert \r\n to \n?
24 win32clipboard.CloseClipboard()
25 return text
26
27 def osx_clipboard_get():
28 """ Get the clipboard's text on OS X.
29 """
30 p = subprocess.Popen(['pbpaste', '-Prefer', 'ascii'],
31 stdout=subprocess.PIPE)
32 text, stderr = p.communicate()
33 # Text comes in with old Mac \r line endings. Change them to \n.
34 text = text.replace('\r', '\n')
35 return text
36
37 def tkinter_clipboard_get():
38 """ Get the clipboard's text using Tkinter.
39
40 This is the default on systems that are not Windows or OS X. It may
41 interfere with other UI toolkits and should be replaced with an
42 implementation that uses that toolkit.
43 """
44 try:
45 import Tkinter
46 except ImportError:
47 message = ("Getting text from the clipboard on this platform "
48 "requires Tkinter.")
49 raise TryNext(message)
50 root = Tkinter.Tk()
51 root.withdraw()
52 text = root.clipboard_get()
53 root.destroy()
54 return text
55
56
@@ -43,8 +43,9 b' somewhere in your configuration files or ipython command line.'
43
43
44 from IPython.core import ipapi
44 from IPython.core import ipapi
45
45
46 import os,bisect
46 import os, bisect
47 from IPython.utils.genutils import Term,shell
47 import sys
48 from IPython.utils.genutils import Term, shell
48 from pprint import PrettyPrinter
49 from pprint import PrettyPrinter
49
50
50 # List here all the default hooks. For now it's just the editor functions
51 # List here all the default hooks. For now it's just the editor functions
@@ -53,7 +54,8 b' from pprint import PrettyPrinter'
53 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display',
54 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display',
54 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
55 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
55 'generate_prompt', 'generate_output_prompt','shell_hook',
56 'generate_prompt', 'generate_output_prompt','shell_hook',
56 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook']
57 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook',
58 'clipboard_get']
57 # vds: <<
59 # vds: <<
58
60
59 pformat = PrettyPrinter().pformat
61 pformat = PrettyPrinter().pformat
@@ -243,5 +245,22 b' def pre_prompt_hook(self):'
243 def pre_runcode_hook(self):
245 def pre_runcode_hook(self):
244 """ Executed before running the (prefiltered) code in IPython """
246 """ Executed before running the (prefiltered) code in IPython """
245 return None
247 return None
246
247
248
249 def clipboard_get(self):
250 """ Get text from the clipboard.
251 """
252 from IPython.lib.clipboard import (
253 osx_clipboard_get, tkinter_clipboard_get,
254 win32_clipboard_get
255 )
256 if sys.platform == 'win32':
257 chain = [win32_clipboard_get, tkinter_clipboard_get]
258 elif sys.platform == 'darwin':
259 chain = [osx_clipboard_get, tkinter_clipboard_get]
260 else:
261 chain = [tkinter_clipboard_get]
262 dispatcher = CommandChainDispatcher()
263 for func in chain:
264 dispatcher.add(func)
265 text = dispatcher()
266 return text
@@ -3262,6 +3262,61 b' Defaulting color scheme to \'NoColor\'"""'
3262 page(self.shell.pycolorize(cont),
3262 page(self.shell.pycolorize(cont),
3263 screen_lines=self.shell.rc.screen_length)
3263 screen_lines=self.shell.rc.screen_length)
3264
3264
3265 def _rerun_pasted(self):
3266 """ Rerun a previously pasted command.
3267 """
3268 b = self.user_ns.get('pasted_block', None)
3269 if b is None:
3270 raise UsageError('No previous pasted block available')
3271 print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))
3272 exec b in self.user_ns
3273
3274 def _get_pasted_lines(self, sentinel):
3275 """ Yield pasted lines until the user enters the given sentinel value.
3276 """
3277 from IPython.core import iplib
3278 print "Pasting code; enter '%s' alone on the line to stop." % sentinel
3279 while True:
3280 l = iplib.raw_input_original(':')
3281 if l == sentinel:
3282 return
3283 else:
3284 yield l
3285
3286 def _strip_pasted_lines_for_code(self, raw_lines):
3287 """ Strip non-code parts of a sequence of lines to return a block of
3288 code.
3289 """
3290 # Regular expressions that declare text we strip from the input:
3291 strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt
3292 r'^\s*(\s?>)+', # Python input prompt
3293 r'^\s*\.{3,}', # Continuation prompts
3294 r'^\++',
3295 ]
3296
3297 strip_from_start = map(re.compile,strip_re)
3298
3299 lines = []
3300 for l in raw_lines:
3301 for pat in strip_from_start:
3302 l = pat.sub('',l)
3303 lines.append(l)
3304
3305 block = "\n".join(lines) + '\n'
3306 #print "block:\n",block
3307 return block
3308
3309 def _execute_block(self, block, par):
3310 """ Execute a block, or store it in a variable, per the user's request.
3311 """
3312 if not par:
3313 b = textwrap.dedent(block)
3314 self.user_ns['pasted_block'] = b
3315 exec b in self.user_ns
3316 else:
3317 self.user_ns[par] = SList(block.splitlines())
3318 print "Block assigned to '%s'" % par
3319
3265 def magic_cpaste(self, parameter_s=''):
3320 def magic_cpaste(self, parameter_s=''):
3266 """Allows you to paste & execute a pre-formatted code block from clipboard.
3321 """Allows you to paste & execute a pre-formatted code block from clipboard.
3267
3322
@@ -3287,50 +3342,60 b' Defaulting color scheme to \'NoColor\'"""'
3287 will be what was just pasted.
3342 will be what was just pasted.
3288
3343
3289 IPython statements (magics, shell escapes) are not supported (yet).
3344 IPython statements (magics, shell escapes) are not supported (yet).
3345
3346 See also
3347 --------
3348 %paste: automatically pull code from clipboard.
3290 """
3349 """
3350
3291 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
3351 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
3292 par = args.strip()
3352 par = args.strip()
3293 if opts.has_key('r'):
3353 if opts.has_key('r'):
3294 b = self.user_ns.get('pasted_block', None)
3354 self._rerun_pasted()
3295 if b is None:
3296 raise UsageError('No previous pasted block available')
3297 print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))
3298 exec b in self.user_ns
3299 return
3355 return
3300
3356
3301 sentinel = opts.get('s','--')
3357 sentinel = opts.get('s','--')
3302
3358
3303 # Regular expressions that declare text we strip from the input:
3359 block = self._strip_pasted_lines_for_code(
3304 strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt
3360 self._get_pasted_lines(sentinel))
3305 r'^\s*(\s?>)+', # Python input prompt
3306 r'^\s*\.{3,}', # Continuation prompts
3307 r'^\++',
3308 ]
3309
3361
3310 strip_from_start = map(re.compile,strip_re)
3362 self._execute_block(block, par)
3363
3364 def magic_paste(self, parameter_s=''):
3365 """Allows you to paste & execute a pre-formatted code block from clipboard.
3311
3366
3312 from IPython.core import iplib
3367 The text is pulled directly from the clipboard without user
3313 lines = []
3368 intervention.
3314 print "Pasting code; enter '%s' alone on the line to stop." % sentinel
3369
3315 while 1:
3370 The block is dedented prior to execution to enable execution of method
3316 l = iplib.raw_input_original(':')
3371 definitions. '>' and '+' characters at the beginning of a line are
3317 if l ==sentinel:
3372 ignored, to allow pasting directly from e-mails, diff files and
3318 break
3373 doctests (the '...' continuation prompt is also stripped). The
3319
3374 executed block is also assigned to variable named 'pasted_block' for
3320 for pat in strip_from_start:
3375 later editing with '%edit pasted_block'.
3321 l = pat.sub('',l)
3376
3322 lines.append(l)
3377 You can also pass a variable name as an argument, e.g. '%paste foo'.
3323
3378 This assigns the pasted block to variable 'foo' as string, without
3324 block = "\n".join(lines) + '\n'
3379 dedenting or executing it (preceding >>> and + is still stripped)
3325 #print "block:\n",block
3380
3326 if not par:
3381 '%paste -r' re-executes the block previously entered by cpaste.
3327 b = textwrap.dedent(block)
3382
3328 self.user_ns['pasted_block'] = b
3383 IPython statements (magics, shell escapes) are not supported (yet).
3329 exec b in self.user_ns
3384
3330 else:
3385 See also
3331 self.user_ns[par] = SList(block.splitlines())
3386 --------
3332 print "Block assigned to '%s'" % par
3387 %cpaste: manually paste code into terminal until you mark its end.
3333
3388 """
3389 opts,args = self.parse_options(parameter_s,'r:',mode='string')
3390 par = args.strip()
3391 if opts.has_key('r'):
3392 self._rerun_pasted()
3393 return
3394
3395 text = self.shell.hooks.clipboard_get()
3396 block = self._strip_pasted_lines_for_code(text.splitlines())
3397 self._execute_block(block, par)
3398
3334 def magic_quickref(self,arg):
3399 def magic_quickref(self,arg):
3335 """ Show a quick reference sheet """
3400 """ Show a quick reference sheet """
3336 import IPython.core.usage
3401 import IPython.core.usage
@@ -252,3 +252,39 b' class TestMagicRun(object):'
252
252
253 def teardown(self):
253 def teardown(self):
254 self.tmpfile.close()
254 self.tmpfile.close()
255
256 # Multiple tests for clipboard pasting
257 def test_paste():
258
259 def paste(txt):
260 hooks.clipboard_get = lambda : txt
261 _ip.magic('paste')
262
263 # Inject fake clipboard hook but save original so we can restore it later
264 hooks = _ip.IP.hooks
265 user_ns = _ip.user_ns
266 original_clip = hooks.clipboard_get
267
268 try:
269 # Run tests with fake clipboard function
270 user_ns.pop('x', None)
271 paste('x=1')
272 yield (nt.assert_equal, user_ns['x'], 1)
273
274 user_ns.pop('x', None)
275 paste('>>> x=2')
276 yield (nt.assert_equal, user_ns['x'], 2)
277
278 paste("""
279 >>> x = [1,2,3]
280 >>> y = []
281 >>> for i in x:
282 ... y.append(i**2)
283 ...
284 """)
285 yield (nt.assert_equal, user_ns['x'], [1,2,3])
286 yield (nt.assert_equal, user_ns['y'], [1,4,9])
287
288 finally:
289 # Restore original hook
290 hooks.clipboard_get = original_clip
General Comments 0
You need to be logged in to leave comments. Login now