Repository: pandas-dev/pandas

Issue:
to_clipboard() required xsel to be installed in Linux
Must be mentioned somewhere, or atleast the message should be more helpful. I saw the Popen failing and installed xsel and it worked.
The last error line was 

```
OSError: [Errno 2] No such file or directory
```



Discussion:
it's in the doc string

that's one reason we need in docs
(to put a warning up)

Sure. Thats for Linux, anything else needed for other OS? 
Can the error message be made more useful for the user, maybe like, 
Missing Dependency: Install ...

sure....error message could def be better

if you want to attempt on windows

I think you can grab the clipboard via py32win.....

if you want to investigate would be great

Fixing the exception message could be as simple as this: https://github.com/hayd/pandas/commit/8d0a57e7f352780ab7f48b2081df57418a675a27 ?

~~(if I could spell platform / write one sentence.)~~

Don't use Windows, so can't try this!

On Mon, Jun 10, 2013 at 11:31 PM, jreback notifications@github.com wrote:

> sure....error message could def be better
> 
> if you want to attempt on windows
> 
> I think you can grab the clipboard via py32win.....
> 
> if you want to investigate would be great
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/pydata/pandas/issues/3837#issuecomment-19215681
> .

http://coffeeghost.net/src/pyperclip.py

this looks like it handles all platforms
I think license compatible too
and is pretty short


Resolving patch:
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -492,6 +492,16 @@ def to_hdf(self, path_or_buf, key, **kwargs):
         return pytables.to_hdf(path_or_buf, key, self, **kwargs)
 
     def to_clipboard(self):
+        """
+        Attempt to write text representation of object to the system clipboard
+
+        Notes
+        -----
+        Requirements for your platform
+          - Linux: xclip, or xsel (with gtk or PyQt4 modules)
+          - Windows:
+          - OS X:
+        """
         from pandas.io import clipboard
         clipboard.to_clipboard(self)
 
diff --git a/pandas/io/clipboard.py b/pandas/io/clipboard.py
--- a/pandas/io/clipboard.py
+++ b/pandas/io/clipboard.py
@@ -23,8 +23,8 @@ def to_clipboard(obj):  # pragma: no cover
     Notes
     -----
     Requirements for your platform
-      - Linux: xsel command line tool
-      - Windows: Python win32 extensions
+      - Linux: xclip, or xsel (with gtk or PyQt4 modules)
+      - Windows:
       - OS X:
     """
     from pandas.util.clipboard import clipboard_set
diff --git a/pandas/util/clipboard.py b/pandas/util/clipboard.py
--- a/pandas/util/clipboard.py
+++ b/pandas/util/clipboard.py
@@ -1,119 +1,160 @@
-"""
-Taken from the IPython project http://ipython.org
-
-Used under the terms of the BSD license
-"""
-
-import subprocess
-import sys
-
-
-def clipboard_get():
-    """ Get text from the clipboard.
-    """
-    if sys.platform == 'win32':
-        try:
-            return win32_clipboard_get()
-        except Exception:
-            pass
-    elif sys.platform == 'darwin':
-        try:
-            return osx_clipboard_get()
-        except Exception:
-            pass
-    return tkinter_clipboard_get()
-
-
-def clipboard_set(text):
-    """ Get text from the clipboard.
-    """
-    if sys.platform == 'win32':
-        try:
-            return win32_clipboard_set(text)
-        except Exception:
-            raise
-    elif sys.platform == 'darwin':
-        try:
-            return osx_clipboard_set(text)
-        except Exception:
-            pass
-    xsel_clipboard_set(text)
-
-
-def win32_clipboard_get():
-    """ Get the current clipboard's text on Windows.
-
-    Requires Mark Hammond's pywin32 extensions.
-    """
-    try:
-        import win32clipboard
-    except ImportError:
-        message = ("Getting text from the clipboard requires the pywin32 "
-                   "extensions: http://sourceforge.net/projects/pywin32/")
-        raise Exception(message)
-    win32clipboard.OpenClipboard()
-    text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
-    # FIXME: convert \r\n to \n?
-    win32clipboard.CloseClipboard()
-    return text
-
-
-def osx_clipboard_get():
-    """ Get the clipboard's text on OS X.
-    """
-    p = subprocess.Popen(['pbpaste', '-Prefer', 'ascii'],
-                         stdout=subprocess.PIPE)
-    text, stderr = p.communicate()
-    # Text comes in with old Mac \r line endings. Change them to \n.
-    text = text.replace('\r', '\n')
-    return text
-
-
-def tkinter_clipboard_get():
-    """ Get the clipboard's text using Tkinter.
-
-    This is the default on systems that are not Windows or OS X. It may
-    interfere with other UI toolkits and should be replaced with an
-    implementation that uses that toolkit.
-    """
+# Pyperclip v1.3
+# A cross-platform clipboard module for Python. (only handles plain text for now)
+# By Al Sweigart al@coffeeghost.net
+
+# Usage:
+#   import pyperclip
+#   pyperclip.copy('The text to be copied to the clipboard.')
+#   spam = pyperclip.paste()
+
+# On Mac, this module makes use of the pbcopy and pbpaste commands, which should come with the os.
+# On Linux, this module makes use of the xclip command, which should come with the os. Otherwise run "sudo apt-get install xclip"
+
+
+# Copyright (c) 2010, Albert Sweigart
+# All rights reserved.
+#
+# BSD-style license:
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the pyperclip nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY Albert Sweigart "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL Albert Sweigart BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Change Log:
+# 1.2 Use the platform module to help determine OS.
+# 1.3 Changed ctypes.windll.user32.OpenClipboard(None) to ctypes.windll.user32.OpenClipboard(0), after some people ran into some TypeError
+
+import platform, os
+
+def winGetClipboard():
+    ctypes.windll.user32.OpenClipboard(0)
+    pcontents = ctypes.windll.user32.GetClipboardData(1) # 1 is CF_TEXT
+    data = ctypes.c_char_p(pcontents).value
+    #ctypes.windll.kernel32.GlobalUnlock(pcontents)
+    ctypes.windll.user32.CloseClipboard()
+    return data
+
+def winSetClipboard(text):
+    GMEM_DDESHARE = 0x2000
+    ctypes.windll.user32.OpenClipboard(0)
+    ctypes.windll.user32.EmptyClipboard()
     try:
-        import Tkinter
-    except ImportError:
-        message = ("Getting text from the clipboard on this platform "
-                   "requires Tkinter.")
-        raise Exception(message)
-    root = Tkinter.Tk()
-    root.withdraw()
-    text = root.clipboard_get()
-    root.destroy()
-    return text
-
-
-def win32_clipboard_set(text):
-    # idiosyncratic win32 import issues
-    import pywintypes as _
-    import win32clipboard
-    win32clipboard.OpenClipboard()
+        # works on Python 2 (bytes() only takes one argument)
+        hCd = ctypes.windll.kernel32.GlobalAlloc(GMEM_DDESHARE, len(bytes(text))+1)
+    except TypeError:
+        # works on Python 3 (bytes() requires an encoding)
+        hCd = ctypes.windll.kernel32.GlobalAlloc(GMEM_DDESHARE, len(bytes(text, 'ascii'))+1)
+    pchData = ctypes.windll.kernel32.GlobalLock(hCd)
     try:
-        win32clipboard.EmptyClipboard()
-        win32clipboard.SetClipboardText(_fix_line_endings(text))
-    finally:
-        win32clipboard.CloseClipboard()
-
-
-def _fix_line_endings(text):
-    return '\r\n'.join(text.splitlines())
-
-
-def osx_clipboard_set(text):
-    """ Get the clipboard's text on OS X.
-    """
-    p = subprocess.Popen(['pbcopy', '-Prefer', 'ascii'],
-                         stdin=subprocess.PIPE)
-    p.communicate(input=text)
-
-
-def xsel_clipboard_set(text):
-    from subprocess import Popen, PIPE
-    p = Popen(['xsel', '-bi'], stdin=PIPE)
-    p.communicate(input=text)
+        # works on Python 2 (bytes() only takes one argument)
+        ctypes.cdll.msvcrt.strcpy(ctypes.c_char_p(pchData), bytes(text))
+    except TypeError:
+        # works on Python 3 (bytes() requires an encoding)
+        ctypes.cdll.msvcrt.strcpy(ctypes.c_char_p(pchData), bytes(text, 'ascii'))
+    ctypes.windll.kernel32.GlobalUnlock(hCd)
+    ctypes.windll.user32.SetClipboardData(1,hCd)
+    ctypes.windll.user32.CloseClipboard()
+
+def macSetClipboard(text):
+    outf = os.popen('pbcopy', 'w')
+    outf.write(text)
+    outf.close()
+
+def macGetClipboard():
+    outf = os.popen('pbpaste', 'r')
+    content = outf.read()
+    outf.close()
+    return content
+
+def gtkGetClipboard():
+    return gtk.Clipboard().wait_for_text()
+
+def gtkSetClipboard(text):
+    cb = gtk.Clipboard()
+    cb.set_text(text)
+    cb.store()
+
+def qtGetClipboard():
+    return str(cb.text())
+
+def qtSetClipboard(text):
+    cb.setText(text)
+
+def xclipSetClipboard(text):
+    outf = os.popen('xclip -selection c', 'w')
+    outf.write(text)
+    outf.close()
+
+def xclipGetClipboard():
+    outf = os.popen('xclip -selection c -o', 'r')
+    content = outf.read()
+    outf.close()
+    return content
+
+def xselSetClipboard(text):
+    outf = os.popen('xsel -i', 'w')
+    outf.write(text)
+    outf.close()
+
+def xselGetClipboard():
+    outf = os.popen('xsel -o', 'r')
+    content = outf.read()
+    outf.close()
+    return content
+
+
+if os.name == 'nt' or platform.system() == 'Windows':
+    import ctypes
+    getcb = winGetClipboard
+    setcb = winSetClipboard
+elif os.name == 'mac' or platform.system() == 'Darwin':
+    getcb = macGetClipboard
+    setcb = macSetClipboard
+elif os.name == 'posix' or platform.system() == 'Linux':
+    xclipExists = os.system('which xclip') == 0
+    if xclipExists:
+        getcb = xclipGetClipboard
+        setcb = xclipSetClipboard
+    else:
+        xselExists = os.system('which xsel') == 0
+        if xselExists:
+            getcb = xselGetClipboard
+            setcb = xselSetClipboard
+        try:
+            import gtk
+            getcb = gtkGetClipboard
+            setcb = gtkSetClipboard
+        except:
+            try:
+                import PyQt4.QtCore
+                import PyQt4.QtGui
+                app = QApplication([])
+                cb = PyQt4.QtGui.QApplication.clipboard()
+                getcb = qtGetClipboard
+                setcb = qtSetClipboard
+            except:
+                raise Exception('Pyperclip requires the gtk or PyQt4 module installed, or the xclip command.')
+copy = setcb
+paste = getcb
+
+## pandas aliases
+clipboard_get = paste
+clipboard_set = copy
\ No newline at end of file


Test patch: