diff --git a/IPython/lib/clipboard.py b/IPython/lib/clipboard.py index 4dc6e45..3bc444f 100644 --- a/IPython/lib/clipboard.py +++ b/IPython/lib/clipboard.py @@ -6,6 +6,9 @@ import subprocess from IPython.core.error import TryNext import IPython.utils.py3compat as py3compat +class ClipboardEmpty(ValueError): + pass + def win32_clipboard_get(): """ Get the current clipboard's text on Windows. @@ -17,9 +20,16 @@ def win32_clipboard_get(): raise TryNext("Getting text from the clipboard requires the pywin32 " "extensions: http://sourceforge.net/projects/pywin32/") win32clipboard.OpenClipboard() - text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT) - # FIXME: convert \r\n to \n? - win32clipboard.CloseClipboard() + try: + text = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT) + except TypeError: + try: + text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT) + text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING) + except TypeError: + raise ClipboardEmpty + finally: + win32clipboard.CloseClipboard() return text def osx_clipboard_get(): @@ -41,17 +51,21 @@ def tkinter_clipboard_get(): implementation that uses that toolkit. """ try: - from tkinter import Tk # Py 3 + from tkinter import Tk, TclError # Py 3 except ImportError: try: - from Tkinter import Tk # Py 2 + from Tkinter import Tk, TclError # Py 2 except ImportError: raise TryNext("Getting text from the clipboard on this platform " "requires Tkinter.") root = Tk() root.withdraw() - text = root.clipboard_get() - root.destroy() + try: + text = root.clipboard_get() + except TclError: + raise ClipboardEmpty + finally: + root.destroy() text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING) return text diff --git a/IPython/lib/tests/test_clipboard.py b/IPython/lib/tests/test_clipboard.py new file mode 100644 index 0000000..2eb9a29 --- /dev/null +++ b/IPython/lib/tests/test_clipboard.py @@ -0,0 +1,20 @@ +import nose.tools as nt + +from IPython.core.error import TryNext +from IPython.lib.clipboard import ClipboardEmpty +from IPython.utils.py3compat import unicode_type + +def test_clipboard_get(): + # Smoketest for clipboard access - we can't easily guarantee that the + # clipboard is accessible and has something on it, but this tries to + # exercise the relevant code anyway. + try: + a = get_ipython().hooks.clipboard_get() + except ClipboardEmpty: + # Nothing in clipboard to get + pass + except TryNext: + # No clipboard access API available + pass + else: + nt.assert_is_instance(a, unicode_type) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 6e49c52..f281dc2 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -24,6 +24,7 @@ from IPython.core.usage import interactive_usage, default_banner from IPython.core.inputsplitter import IPythonInputSplitter from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC from IPython.core.magic import Magics, magics_class, line_magic +from IPython.lib.clipboard import ClipboardEmpty from IPython.testing.skipdoctest import skip_doctest from IPython.utils.encoding import get_stream_enc from IPython.utils import py3compat @@ -216,6 +217,8 @@ class TerminalMagics(Magics): else: error('Could not get text from the clipboard.') return + except ClipboardEmpty: + raise UsageError("The clipboard appears to be empty") # By default, echo back to terminal unless quiet mode is requested if 'q' not in opts: