From 414a88dc56626f0edf9a181df81c48e33c8ab632 2013-10-30 00:40:52
From: Thomas Kluyver <takowl@gmail.com>
Date: 2013-10-30 00:40:52
Subject: [PATCH] Better clipboard handling, esp. with pywin32

Ensure that we get unicode from the clipboard when using pywin32.
Closes gh-3386

Also catches the empty clipboard case and displays a short error
message, instead of a huge traceback.

---

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/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: