Skip to content

Commit a7d069d

Browse files
committed
ENH use pyperclip for read and to_clipboard
1 parent 5bf1d9c commit a7d069d

File tree

1 file changed

+158
-117
lines changed

1 file changed

+158
-117
lines changed

pandas/util/clipboard.py

Lines changed: 158 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,160 @@
1-
"""
2-
Taken from the IPython project http://ipython.org
3-
4-
Used under the terms of the BSD license
5-
"""
6-
7-
import subprocess
8-
import sys
9-
10-
11-
def clipboard_get():
12-
""" Get text from the clipboard.
13-
"""
14-
if sys.platform == 'win32':
15-
try:
16-
return win32_clipboard_get()
17-
except Exception:
18-
pass
19-
elif sys.platform == 'darwin':
20-
try:
21-
return osx_clipboard_get()
22-
except Exception:
23-
pass
24-
return tkinter_clipboard_get()
25-
26-
27-
def clipboard_set(text):
28-
""" Get text from the clipboard.
29-
"""
30-
if sys.platform == 'win32':
31-
try:
32-
return win32_clipboard_set(text)
33-
except Exception:
34-
raise
35-
elif sys.platform == 'darwin':
36-
try:
37-
return osx_clipboard_set(text)
38-
except Exception:
39-
pass
40-
xsel_clipboard_set(text)
41-
42-
43-
def win32_clipboard_get():
44-
""" Get the current clipboard's text on Windows.
45-
46-
Requires Mark Hammond's pywin32 extensions.
47-
"""
48-
try:
49-
import win32clipboard
50-
except ImportError:
51-
message = ("Getting text from the clipboard requires the pywin32 "
52-
"extensions: http://sourceforge.net/projects/pywin32/")
53-
raise Exception(message)
54-
win32clipboard.OpenClipboard()
55-
text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
56-
# FIXME: convert \r\n to \n?
57-
win32clipboard.CloseClipboard()
58-
return text
59-
60-
61-
def osx_clipboard_get():
62-
""" Get the clipboard's text on OS X.
63-
"""
64-
p = subprocess.Popen(['pbpaste', '-Prefer', 'ascii'],
65-
stdout=subprocess.PIPE)
66-
text, stderr = p.communicate()
67-
# Text comes in with old Mac \r line endings. Change them to \n.
68-
text = text.replace('\r', '\n')
69-
return text
70-
71-
72-
def tkinter_clipboard_get():
73-
""" Get the clipboard's text using Tkinter.
74-
75-
This is the default on systems that are not Windows or OS X. It may
76-
interfere with other UI toolkits and should be replaced with an
77-
implementation that uses that toolkit.
78-
"""
1+
# Pyperclip v1.3
2+
# A cross-platform clipboard module for Python. (only handles plain text for now)
3+
# By Al Sweigart [email protected]
4+
5+
# Usage:
6+
# import pyperclip
7+
# pyperclip.copy('The text to be copied to the clipboard.')
8+
# spam = pyperclip.paste()
9+
10+
# On Mac, this module makes use of the pbcopy and pbpaste commands, which should come with the os.
11+
# On Linux, this module makes use of the xclip command, which should come with the os. Otherwise run "sudo apt-get install xclip"
12+
13+
14+
# Copyright (c) 2010, Albert Sweigart
15+
# All rights reserved.
16+
#
17+
# BSD-style license:
18+
#
19+
# Redistribution and use in source and binary forms, with or without
20+
# modification, are permitted provided that the following conditions are met:
21+
# * Redistributions of source code must retain the above copyright
22+
# notice, this list of conditions and the following disclaimer.
23+
# * Redistributions in binary form must reproduce the above copyright
24+
# notice, this list of conditions and the following disclaimer in the
25+
# documentation and/or other materials provided with the distribution.
26+
# * Neither the name of the pyperclip nor the
27+
# names of its contributors may be used to endorse or promote products
28+
# derived from this software without specific prior written permission.
29+
#
30+
# THIS SOFTWARE IS PROVIDED BY Albert Sweigart "AS IS" AND ANY
31+
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33+
# DISCLAIMED. IN NO EVENT SHALL Albert Sweigart BE LIABLE FOR ANY
34+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
37+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40+
41+
# Change Log:
42+
# 1.2 Use the platform module to help determine OS.
43+
# 1.3 Changed ctypes.windll.user32.OpenClipboard(None) to ctypes.windll.user32.OpenClipboard(0), after some people ran into some TypeError
44+
45+
import platform, os
46+
47+
def winGetClipboard():
48+
ctypes.windll.user32.OpenClipboard(0)
49+
pcontents = ctypes.windll.user32.GetClipboardData(1) # 1 is CF_TEXT
50+
data = ctypes.c_char_p(pcontents).value
51+
#ctypes.windll.kernel32.GlobalUnlock(pcontents)
52+
ctypes.windll.user32.CloseClipboard()
53+
return data
54+
55+
def winSetClipboard(text):
56+
GMEM_DDESHARE = 0x2000
57+
ctypes.windll.user32.OpenClipboard(0)
58+
ctypes.windll.user32.EmptyClipboard()
7959
try:
80-
import Tkinter
81-
except ImportError:
82-
message = ("Getting text from the clipboard on this platform "
83-
"requires Tkinter.")
84-
raise Exception(message)
85-
root = Tkinter.Tk()
86-
root.withdraw()
87-
text = root.clipboard_get()
88-
root.destroy()
89-
return text
90-
91-
92-
def win32_clipboard_set(text):
93-
# idiosyncratic win32 import issues
94-
import pywintypes as _
95-
import win32clipboard
96-
win32clipboard.OpenClipboard()
60+
# works on Python 2 (bytes() only takes one argument)
61+
hCd = ctypes.windll.kernel32.GlobalAlloc(GMEM_DDESHARE, len(bytes(text))+1)
62+
except TypeError:
63+
# works on Python 3 (bytes() requires an encoding)
64+
hCd = ctypes.windll.kernel32.GlobalAlloc(GMEM_DDESHARE, len(bytes(text, 'ascii'))+1)
65+
pchData = ctypes.windll.kernel32.GlobalLock(hCd)
9766
try:
98-
win32clipboard.EmptyClipboard()
99-
win32clipboard.SetClipboardText(_fix_line_endings(text))
100-
finally:
101-
win32clipboard.CloseClipboard()
102-
103-
104-
def _fix_line_endings(text):
105-
return '\r\n'.join(text.splitlines())
106-
107-
108-
def osx_clipboard_set(text):
109-
""" Get the clipboard's text on OS X.
110-
"""
111-
p = subprocess.Popen(['pbcopy', '-Prefer', 'ascii'],
112-
stdin=subprocess.PIPE)
113-
p.communicate(input=text)
114-
115-
116-
def xsel_clipboard_set(text):
117-
from subprocess import Popen, PIPE
118-
p = Popen(['xsel', '-bi'], stdin=PIPE)
119-
p.communicate(input=text)
67+
# works on Python 2 (bytes() only takes one argument)
68+
ctypes.cdll.msvcrt.strcpy(ctypes.c_char_p(pchData), bytes(text))
69+
except TypeError:
70+
# works on Python 3 (bytes() requires an encoding)
71+
ctypes.cdll.msvcrt.strcpy(ctypes.c_char_p(pchData), bytes(text, 'ascii'))
72+
ctypes.windll.kernel32.GlobalUnlock(hCd)
73+
ctypes.windll.user32.SetClipboardData(1,hCd)
74+
ctypes.windll.user32.CloseClipboard()
75+
76+
def macSetClipboard(text):
77+
outf = os.popen('pbcopy', 'w')
78+
outf.write(text)
79+
outf.close()
80+
81+
def macGetClipboard():
82+
outf = os.popen('pbpaste', 'r')
83+
content = outf.read()
84+
outf.close()
85+
return content
86+
87+
def gtkGetClipboard():
88+
return gtk.Clipboard().wait_for_text()
89+
90+
def gtkSetClipboard(text):
91+
cb = gtk.Clipboard()
92+
cb.set_text(text)
93+
cb.store()
94+
95+
def qtGetClipboard():
96+
return str(cb.text())
97+
98+
def qtSetClipboard(text):
99+
cb.setText(text)
100+
101+
def xclipSetClipboard(text):
102+
outf = os.popen('xclip -selection c', 'w')
103+
outf.write(text)
104+
outf.close()
105+
106+
def xclipGetClipboard():
107+
outf = os.popen('xclip -selection c -o', 'r')
108+
content = outf.read()
109+
outf.close()
110+
return content
111+
112+
def xselSetClipboard(text):
113+
outf = os.popen('xsel -i', 'w')
114+
outf.write(text)
115+
outf.close()
116+
117+
def xselGetClipboard():
118+
outf = os.popen('xsel -o', 'r')
119+
content = outf.read()
120+
outf.close()
121+
return content
122+
123+
124+
if os.name == 'nt' or platform.system() == 'Windows':
125+
import ctypes
126+
getcb = winGetClipboard
127+
setcb = winSetClipboard
128+
elif os.name == 'mac' or platform.system() == 'Darwin':
129+
getcb = macGetClipboard
130+
setcb = macSetClipboard
131+
elif os.name == 'posix' or platform.system() == 'Linux':
132+
xclipExists = os.system('which xclip') == 0
133+
if xclipExists:
134+
getcb = xclipGetClipboard
135+
setcb = xclipSetClipboard
136+
else:
137+
xselExists = os.system('which xsel') == 0
138+
if xselExists:
139+
getcb = xselGetClipboard
140+
setcb = xselSetClipboard
141+
try:
142+
import gtk
143+
getcb = gtkGetClipboard
144+
setcb = gtkSetClipboard
145+
except:
146+
try:
147+
import PyQt4.QtCore
148+
import PyQt4.QtGui
149+
app = QApplication([])
150+
cb = PyQt4.QtGui.QApplication.clipboard()
151+
getcb = qtGetClipboard
152+
setcb = qtSetClipboard
153+
except:
154+
raise Exception('Pyperclip requires the gtk or PyQt4 module installed, or the xclip command.')
155+
copy = setcb
156+
paste = getcb
157+
158+
## pandas aliases
159+
clipboard_get = paste
160+
clipboard_set = copy

0 commit comments

Comments
 (0)