##// 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 44 from IPython.core import ipapi
45 45
46 import os,bisect
47 from IPython.utils.genutils import Term,shell
46 import os, bisect
47 import sys
48 from IPython.utils.genutils import Term, shell
48 49 from pprint import PrettyPrinter
49 50
50 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 54 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display',
54 55 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
55 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 59 # vds: <<
58 60
59 61 pformat = PrettyPrinter().pformat
@@ -243,5 +245,22 b' def pre_prompt_hook(self):'
243 245 def pre_runcode_hook(self):
244 246 """ Executed before running the (prefiltered) code in IPython """
245 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 3262 page(self.shell.pycolorize(cont),
3263 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 3320 def magic_cpaste(self, parameter_s=''):
3266 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 3342 will be what was just pasted.
3288 3343
3289 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 3351 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
3292 3352 par = args.strip()
3293 3353 if opts.has_key('r'):
3294 b = self.user_ns.get('pasted_block', None)
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
3354 self._rerun_pasted()
3299 3355 return
3300 3356
3301 3357 sentinel = opts.get('s','--')
3302 3358
3303 # Regular expressions that declare text we strip from the input:
3304 strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt
3305 r'^\s*(\s?>)+', # Python input prompt
3306 r'^\s*\.{3,}', # Continuation prompts
3307 r'^\++',
3308 ]
3359 block = self._strip_pasted_lines_for_code(
3360 self._get_pasted_lines(sentinel))
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
3313 lines = []
3314 print "Pasting code; enter '%s' alone on the line to stop." % sentinel
3315 while 1:
3316 l = iplib.raw_input_original(':')
3317 if l ==sentinel:
3318 break
3319
3320 for pat in strip_from_start:
3321 l = pat.sub('',l)
3322 lines.append(l)
3323
3324 block = "\n".join(lines) + '\n'
3325 #print "block:\n",block
3326 if not par:
3327 b = textwrap.dedent(block)
3328 self.user_ns['pasted_block'] = b
3329 exec b in self.user_ns
3330 else:
3331 self.user_ns[par] = SList(block.splitlines())
3332 print "Block assigned to '%s'" % par
3333
3367 The text is pulled directly from the clipboard without user
3368 intervention.
3369
3370 The block is dedented prior to execution to enable execution of method
3371 definitions. '>' and '+' characters at the beginning of a line are
3372 ignored, to allow pasting directly from e-mails, diff files and
3373 doctests (the '...' continuation prompt is also stripped). The
3374 executed block is also assigned to variable named 'pasted_block' for
3375 later editing with '%edit pasted_block'.
3376
3377 You can also pass a variable name as an argument, e.g. '%paste foo'.
3378 This assigns the pasted block to variable 'foo' as string, without
3379 dedenting or executing it (preceding >>> and + is still stripped)
3380
3381 '%paste -r' re-executes the block previously entered by cpaste.
3382
3383 IPython statements (magics, shell escapes) are not supported (yet).
3384
3385 See also
3386 --------
3387 %cpaste: manually paste code into terminal until you mark its end.
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 3399 def magic_quickref(self,arg):
3335 3400 """ Show a quick reference sheet """
3336 3401 import IPython.core.usage
@@ -252,3 +252,39 b' class TestMagicRun(object):'
252 252
253 253 def teardown(self):
254 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