Related
I wrote a kernel module that writes in /proc/mydev to notify the python program in userspace. I want to trigger a function in the python program whenever there is an update of data in /proc/mydev from the kernel module. What is the best way to listen for an update here? I am thinking about using "watchdog" (https://pythonhosted.org/watchdog/). Is there a better way for this?
This is an easy and efficient way:
import os
from time import sleep
from datetime import datetime
def myfuction(_time):
print("file modified, time: "+datetime.fromtimestamp(_time).strftime("%H:%M:%S"))
if __name__ == "__main__":
_time = 0
while True:
last_modified_time = os.stat("/proc/mydev").st_mtime
if last_modified_time > _time:
myfuction(last_modified_time)
_time = last_modified_time
sleep(1) # prevent high cpu usage
result:
file modified, time: 11:44:09
file modified, time: 11:46:15
file modified, time: 11:46:24
The while loop guarantees that the program keeps listening to changes forever.
You can set the interval by changing the sleep time. Low sleep time causes high CPU usage.
import time
import os
# get the file descriptor for the proc file
fd = os.open("/proc/mydev", os.O_RDONLY)
# create a polling object to monitor the file for updates
poller = select.poll()
poller.register(fd, select.POLLIN)
# create a loop to monitor the file for updates
while True:
events = poller.poll(10000)
if len(events) > 0:
# read the contents of the file if updated
print(os.read(fd, 1024))
sudo pip install inotify
Example
Code for monitoring a simple, flat path (see “Recursive Watching” for watching a hierarchical structure):
import inotify.adapters
def _main():
i = inotify.adapters.Inotify()
i.add_watch('/tmp')
with open('/tmp/test_file', 'w'):
pass
for event in i.event_gen(yield_nones=False):
(_, type_names, path, filename) = event
print("PATH=[{}] FILENAME=[{}] EVENT_TYPES={}".format(
path, filename, type_names))
if __name__ == '__main__':
_main()
Expected output:
PATH=[/tmp] FILENAME=[test_file] EVENT_TYPES=['IN_MODIFY']
PATH=[/tmp] FILENAME=[test_file] EVENT_TYPES=['IN_OPEN']
PATH=[/tmp] FILENAME=[test_file] EVENT_TYPES=['IN_CLOSE_WRITE']
I'm not sure if this would work for your situation, since it seems that you're wanting to watch a folder, but this program watches a file at a time until the main() loop repeats:
import os
import time
def main():
contents = os.listdir("/proc/mydev")
for file in contents:
f = open("/proc/mydev/" + file, "r")
init = f.read()
f.close()
while different = false:
f = open("/proc/mydev/" + file, "r")
check = f.read()
f.close()
if init !== check:
different = true
else:
different = false
time.sleep(1)
main()
# Write what you would want to happen if a change occured here...
main()
main()
main()
You could then write what you would want to happen right before the last usage of main(), as it would then repeat.
Also, this may contain errors, since I rushed this.
Hope this at least helps!
You can't do this efficiently without modifying your kernel driver.
Instead of using procfs, have it register a new character device under /dev, and write that driver to make new content available to read from that device only when new content has in fact come in from the underlying hardware, such that the application layer can issue a blocking read and have it return only when new content exists.
A good example to work from (which also has plenty of native Python clients) is the evdev devices in the input core.
I'm trying to make a basic Windows application that builds a string out of user input and then adds it to the clipboard. How do I copy a string to the clipboard using Python?
Actually, pywin32 and ctypes seem to be an overkill for this simple task. tkinter is a cross-platform GUI framework, which ships with Python by default and has clipboard accessing methods along with other cool stuff.
If all you need is to put some text to system clipboard, this will do it:
from tkinter import Tk # in Python 2, use "Tkinter" instead
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append('i can has clipboardz?')
r.update() # now it stays on the clipboard after the window is closed
r.destroy()
And that's all, no need to mess around with platform-specific third-party libraries.
If you are using Python 2, replace tkinter with Tkinter.
I didn't have a solution, just a workaround.
Windows Vista onwards has an inbuilt command called clip that takes the output of a command from command line and puts it into the clipboard. For example, ipconfig | clip.
So I made a function with the os module which takes a string and adds it to the clipboard using the inbuilt Windows solution.
import os
def addToClipBoard(text):
command = 'echo ' + text.strip() + '| clip'
os.system(command)
# Example
addToClipBoard('penny lane')
# Penny Lane is now in your ears, eyes, and clipboard.
As previously noted in the comments however, one downside to this approach is that the echo command automatically adds a newline to the end of your text. To avoid this you can use a modified version of the command:
def addToClipBoard(text):
command = 'echo | set /p nul=' + text.strip() + '| clip'
os.system(command)
If you are using Windows XP it will work just following the steps in Copy and paste from Windows XP Pro's command prompt straight to the Clipboard.
You can use pyperclip - cross-platform clipboard module. Or Xerox - similar module, except requires the win32 Python module to work on Windows.
You can also use ctypes to tap into the Windows API and avoid the massive pywin32 package. This is what I use (excuse the poor style, but the idea is there):
import ctypes
# Get required functions, strcpy..
strcpy = ctypes.cdll.msvcrt.strcpy
ocb = ctypes.windll.user32.OpenClipboard # Basic clipboard functions
ecb = ctypes.windll.user32.EmptyClipboard
gcd = ctypes.windll.user32.GetClipboardData
scd = ctypes.windll.user32.SetClipboardData
ccb = ctypes.windll.user32.CloseClipboard
ga = ctypes.windll.kernel32.GlobalAlloc # Global memory allocation
gl = ctypes.windll.kernel32.GlobalLock # Global memory Locking
gul = ctypes.windll.kernel32.GlobalUnlock
GMEM_DDESHARE = 0x2000
def Get():
ocb(None) # Open Clip, Default task
pcontents = gcd(1) # 1 means CF_TEXT.. too lazy to get the token thingy...
data = ctypes.c_char_p(pcontents).value
#gul(pcontents) ?
ccb()
return data
def Paste(data):
ocb(None) # Open Clip, Default task
ecb()
hCd = ga(GMEM_DDESHARE, len(bytes(data,"ascii")) + 1)
pchData = gl(hCd)
strcpy(ctypes.c_char_p(pchData), bytes(data, "ascii"))
gul(hCd)
scd(1, hCd)
ccb()
The simplest way is with pyperclip. Works in python 2 and 3.
To install this library, use:
pip install pyperclip
Example usage:
import pyperclip
pyperclip.copy("your string")
If you want to get the contents of the clipboard:
clipboard_content = pyperclip.paste()
You can use the excellent pandas, which has a built in clipboard support, but you need to pass through a DataFrame.
import pandas as pd
df=pd.DataFrame(['Text to copy'])
df.to_clipboard(index=False,header=False)
Here's the most easy and reliable way I found if you're okay depending on Pandas. However I don't think this is officially part of the Pandas API so it may break with future updates. It works as of 0.25.3
from pandas.io import clipboard
clipboard.copy("test")
For some reason I've never been able to get the Tk solution to work for me. kapace's solution is much more workable, but the formatting is contrary to my style and it doesn't work with Unicode. Here's a modified version.
import ctypes
from ctypes.wintypes import BOOL, HWND, HANDLE, HGLOBAL, UINT, LPVOID
from ctypes import c_size_t as SIZE_T
OpenClipboard = ctypes.windll.user32.OpenClipboard
OpenClipboard.argtypes = HWND,
OpenClipboard.restype = BOOL
EmptyClipboard = ctypes.windll.user32.EmptyClipboard
EmptyClipboard.restype = BOOL
GetClipboardData = ctypes.windll.user32.GetClipboardData
GetClipboardData.argtypes = UINT,
GetClipboardData.restype = HANDLE
SetClipboardData = ctypes.windll.user32.SetClipboardData
SetClipboardData.argtypes = UINT, HANDLE
SetClipboardData.restype = HANDLE
CloseClipboard = ctypes.windll.user32.CloseClipboard
CloseClipboard.restype = BOOL
CF_UNICODETEXT = 13
GlobalAlloc = ctypes.windll.kernel32.GlobalAlloc
GlobalAlloc.argtypes = UINT, SIZE_T
GlobalAlloc.restype = HGLOBAL
GlobalLock = ctypes.windll.kernel32.GlobalLock
GlobalLock.argtypes = HGLOBAL,
GlobalLock.restype = LPVOID
GlobalUnlock = ctypes.windll.kernel32.GlobalUnlock
GlobalUnlock.argtypes = HGLOBAL,
GlobalSize = ctypes.windll.kernel32.GlobalSize
GlobalSize.argtypes = HGLOBAL,
GlobalSize.restype = SIZE_T
GMEM_MOVEABLE = 0x0002
GMEM_ZEROINIT = 0x0040
unicode_type = type(u'')
def get():
text = None
OpenClipboard(None)
handle = GetClipboardData(CF_UNICODETEXT)
pcontents = GlobalLock(handle)
size = GlobalSize(handle)
if pcontents and size:
raw_data = ctypes.create_string_buffer(size)
ctypes.memmove(raw_data, pcontents, size)
text = raw_data.raw.decode('utf-16le').rstrip(u'\0')
GlobalUnlock(handle)
CloseClipboard()
return text
def put(s):
if not isinstance(s, unicode_type):
s = s.decode('mbcs')
data = s.encode('utf-16le')
OpenClipboard(None)
EmptyClipboard()
handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, len(data) + 2)
pcontents = GlobalLock(handle)
ctypes.memmove(pcontents, data, len(data))
GlobalUnlock(handle)
SetClipboardData(CF_UNICODETEXT, handle)
CloseClipboard()
paste = get
copy = put
The above has changed since this answer was first created, to better cope with extended Unicode characters and Python 3. It has been tested in both Python 2.7 and 3.5, and works even with emoji such as \U0001f601 (😁).
Update 2021-10-26: This was working great for me in Windows 7 and Python 3.8. Then I got a new computer with Windows 10 and Python 3.10, and it failed for me the same way as indicated in the comments. This post gave me the answer. The functions from ctypes don't have argument and return types properly specified, and the defaults don't work consistently with 64-bit values. I've modified the above code to include that missing information.
I've tried various solutions, but this is the simplest one that passes my test:
#coding=utf-8
import win32clipboard # http://sourceforge.net/projects/pywin32/
def copy(text):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(text, win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
def paste():
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
return data
if __name__ == "__main__":
text = "Testing\nthe “clip—board”: 📋"
try: text = text.decode('utf8') # Python 2 needs decode to make a Unicode string.
except AttributeError: pass
print("%r" % text.encode('utf8'))
copy(text)
data = paste()
print("%r" % data.encode('utf8'))
print("OK" if text == data else "FAIL")
try: print(data)
except UnicodeEncodeError as er:
print(er)
print(data.encode('utf8'))
Tested OK in Python 3.4 on Windows 8.1 and Python 2.7 on Windows 7. Also when reading Unicode data with Unix linefeeds copied from Windows. Copied data stays on the clipboard after Python exits: "Testing
the “clip—board”: 📋"
If you want no external dependencies, use this code (now part of cross-platform pyperclip - C:\Python34\Scripts\pip install --upgrade pyperclip):
def copy(text):
GMEM_DDESHARE = 0x2000
CF_UNICODETEXT = 13
d = ctypes.windll # cdll expects 4 more bytes in user32.OpenClipboard(None)
try: # Python 2
if not isinstance(text, unicode):
text = text.decode('mbcs')
except NameError:
if not isinstance(text, str):
text = text.decode('mbcs')
d.user32.OpenClipboard(0)
d.user32.EmptyClipboard()
hCd = d.kernel32.GlobalAlloc(GMEM_DDESHARE, len(text.encode('utf-16-le')) + 2)
pchData = d.kernel32.GlobalLock(hCd)
ctypes.cdll.msvcrt.wcscpy(ctypes.c_wchar_p(pchData), text)
d.kernel32.GlobalUnlock(hCd)
d.user32.SetClipboardData(CF_UNICODETEXT, hCd)
d.user32.CloseClipboard()
def paste():
CF_UNICODETEXT = 13
d = ctypes.windll
d.user32.OpenClipboard(0)
handle = d.user32.GetClipboardData(CF_UNICODETEXT)
text = ctypes.c_wchar_p(handle).value
d.user32.CloseClipboard()
return text
Use pyperclip module
Install using pip pip install pyperclip.
https://pypi.org/project/pyperclip/
Copy text "Hello World!" to clip board
import pyperclip
pyperclip.copy('Hello World!')
You can use Ctrl+V anywhere to paste this somewhere.
Paste the copied text using python
pyperclip.paste() # This returns the copied text of type <class 'str'>
If you don't like the name you can use the derivative module clipboard.
Note: It's just a selective wrapper of pyperclip
After installing, import it:
import clipboard
Then you can copy like this:
clipboard.copy("This is copied")
You can also paste the copied text:
clipboard.paste()
Looks like you need to add win32clipboard to your site-packages. It's part of the pywin32 package
Not all of the answers worked for my various python configurations so this solution only uses the subprocess module. However, copy_keyword has to be pbcopy for Mac or clip for Windows:
import subprocess
subprocess.run('copy_keyword', universal_newlines=True, input='New Clipboard Value 😀')
Here's some more extensive code that automatically checks what the current operating system is:
import platform
import subprocess
copy_string = 'New Clipboard Value 😀'
# Check which operating system is running to get the correct copying keyword.
if platform.system() == 'Darwin':
copy_keyword = 'pbcopy'
elif platform.system() == 'Windows':
copy_keyword = 'clip'
subprocess.run(copy_keyword, universal_newlines=True, input=copy_string)
I think there is a much simpler solution to this.
name = input('What is your name? ')
print('Hello %s' % (name) )
Then run your program in the command line
python greeter.py | clip
This will pipe the output of your file to the clipboard
Widgets also have method named .clipboard_get() that returns the contents of the clipboard (unless some kind of error happens based on the type of data in the clipboard).
The clipboard_get() method is mentioned in this bug report:
http://bugs.python.org/issue14777
Strangely, this method was not mentioned in the common (but unofficial) online TkInter documentation sources that I usually refer to.
Solution with stdlib, without security issues
The following solution works in Linux without any additional library and without the risk of executing unwanted code in your shell.
import subprocess
def to_clipboard(text: str) -> None:
sp = subprocess.Popen(["xclip"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
sp.communicate(text.encode("utf8"))
Note that there multiple clipboard in Linux, the you use with the Middle Mouse (Primary) and yet another that you use pressing STRG+C,STRG+V.
You can define which clipboard is used by adding a selection parameter i.e. ["xclip", "-selection", "clipboard"].
See the man xclip for details.
If you using Windows, just replace xclip with clip.
This solution works without Tkinter, which not available some Python installations (i.e. the custom build I am currently using).
In addition to Mark Ransom's answer using ctypes:
This does not work for (all?) x64 systems since the handles seem to be truncated to int-size.
Explicitly defining args and return values helps to overcomes this problem.
import ctypes
import ctypes.wintypes as w
CF_UNICODETEXT = 13
u32 = ctypes.WinDLL('user32')
k32 = ctypes.WinDLL('kernel32')
OpenClipboard = u32.OpenClipboard
OpenClipboard.argtypes = w.HWND,
OpenClipboard.restype = w.BOOL
GetClipboardData = u32.GetClipboardData
GetClipboardData.argtypes = w.UINT,
GetClipboardData.restype = w.HANDLE
EmptyClipboard = u32.EmptyClipboard
EmptyClipboard.restype = w.BOOL
SetClipboardData = u32.SetClipboardData
SetClipboardData.argtypes = w.UINT, w.HANDLE,
SetClipboardData.restype = w.HANDLE
CloseClipboard = u32.CloseClipboard
CloseClipboard.argtypes = None
CloseClipboard.restype = w.BOOL
GHND = 0x0042
GlobalAlloc = k32.GlobalAlloc
GlobalAlloc.argtypes = w.UINT, w.ctypes.c_size_t,
GlobalAlloc.restype = w.HGLOBAL
GlobalLock = k32.GlobalLock
GlobalLock.argtypes = w.HGLOBAL,
GlobalLock.restype = w.LPVOID
GlobalUnlock = k32.GlobalUnlock
GlobalUnlock.argtypes = w.HGLOBAL,
GlobalUnlock.restype = w.BOOL
GlobalSize = k32.GlobalSize
GlobalSize.argtypes = w.HGLOBAL,
GlobalSize.restype = w.ctypes.c_size_t
unicode_type = type(u'')
def get():
text = None
OpenClipboard(None)
handle = GetClipboardData(CF_UNICODETEXT)
pcontents = GlobalLock(handle)
size = GlobalSize(handle)
if pcontents and size:
raw_data = ctypes.create_string_buffer(size)
ctypes.memmove(raw_data, pcontents, size)
text = raw_data.raw.decode('utf-16le').rstrip(u'\0')
GlobalUnlock(handle)
CloseClipboard()
return text
def put(s):
if not isinstance(s, unicode_type):
s = s.decode('mbcs')
data = s.encode('utf-16le')
OpenClipboard(None)
EmptyClipboard()
handle = GlobalAlloc(GHND, len(data) + 2)
pcontents = GlobalLock(handle)
ctypes.memmove(pcontents, data, len(data))
GlobalUnlock(handle)
SetClipboardData(CF_UNICODETEXT, handle)
CloseClipboard()
#Test run
paste = get
copy = put
copy("Hello World!")
print(paste())
also you can use > clipboard
import clipboard
def copy(txt):
clipboard.copy(txt)
copy("your txt")
If (and only if) the application already uses Qt, you can use this (with the advantage of no additional third party dependency)
from PyQt5.QtWidgets import QApplication
clipboard = QApplication.clipboard()
# get text (if there's text inside instead of e.g. file)
clipboard.text()
# set text
clipboard.setText(s)
This requires a Qt application object to be already constructed, so it should not be used unless the application already uses Qt.
Besides, as usual, in X systems (and maybe other systems too), the content only persist until the application exists unless you use something like parcellite or xclipboard.
Documentation:
QGuiApplication Class | Qt GUI 5.15.6
QClipboard Class | Qt GUI 5.15.6
See also: python - PyQT - copy file to clipboard - Stack Overflow
import wx
def ctc(text):
if not wx.TheClipboard.IsOpened():
wx.TheClipboard.Open()
data = wx.TextDataObject()
data.SetText(text)
wx.TheClipboard.SetData(data)
wx.TheClipboard.Close()
ctc(text)
The snippet I share here take advantage of the ability to format text files: what if you want to copy a complex output to the clipboard ? (Say a numpy array in column or a list of something)
import subprocess
import os
def cp2clip(clist):
#create a temporary file
fi=open("thisTextfileShouldNotExist.txt","w")
#write in the text file the way you want your data to be
for m in clist:
fi.write(m+"\n")
#close the file
fi.close()
#send "clip < file" to the shell
cmd="clip < thisTextfileShouldNotExist.txt"
w = subprocess.check_call(cmd,shell=True)
#delete the temporary text file
os.remove("thisTextfileShouldNotExist.txt")
return w
works only for windows, can be adapted for linux or mac I guess. Maybe a bit complicated...
example:
>>>cp2clip(["ET","phone","home"])
>>>0
Ctrl+V in any text editor :
ET
phone
home
This is the improved answer of atomizer.
Note 2 calls of update() and 200 ms delay between them. They protect freezing applications due to an unstable state of the clipboard:
from Tkinter import Tk
import time
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append('some string')
r.update()
time.sleep(.2)
r.update()
r.destroy()
Use python's clipboard library!
import clipboard as cp
cp.copy("abc")
Clipboard contains 'abc' now. Happy pasting!
You can use winclip32 module!
install:
pip install winclip32
to copy:
import winclip32
winclip32.set_clipboard_data(winclip32.UNICODE_STD_TEXT, "some text")
to get:
import winclip32
print(winclip32.get_clipboard_data(winclip32.UNICODE_STD_TEXT))
for more informations: https://pypi.org/project/winclip32/
On Windows, you can use this. No external dependencies neither have to open sub-process:
import win32clipboard
def to_clipboard(txt):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(txt)
win32clipboard.CloseClipboard()
My multiplatform solution base on this question:
import subprocess
import distutils.spawn
def clipit(text):
if distutils.spawn.find_executable("xclip"):
# for Linux
subprocess.run(["xclip", "-i"], input=text.encode("utf8"))
elif distutils.spawn.find_executable("xsel"):
# for Linux
subprocess.run(["xsel", "--input"], input=text.encode("utf8"))
elif distutils.spawn.find_executable("clip"):
# for Windows
subprocess.run(["clip"], input=text.encode("utf8"))
else:
import pyperclip
print("I use module pyperclip.")
pyperclip.copy(text)
Code snippet to copy the clipboard:
Create a wrapper Python code in a module named (clipboard.py):
import clr
clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import Clipboard
def setText(text):
Clipboard.SetText(text)
def getText():
return Clipboard.GetText()
Then import the above module into your code.
import io
import clipboard
code = clipboard.getText()
print code
code = "abcd"
clipboard.setText(code)
I must give credit to the blog post Clipboard Access in IronPython.
you can try this:
command = 'echo content |clip'
subprocess.check_call(command, shell=True)
How do you use Python to determine which Linux device/partition contains a given filesystem?
e.g.
>>> get_filesystem_device('/')
/dev/sda
>>> get_filesystem_partition('/')
/dev/sda1
Your question was about Linux, so this is (more or less) linux specific.
Below is code example for three variants for mapping major/minor to a device name.
Parse /proc/partitions.
Ask hal. Hal also keeps track of "parent" device, meaning you can easily get the disk aswell as the partition.
Check sysfs yourself. This is where hal gets its information from.
I'd say that /proc/partitions is simplest - it is just one file to open and check. hal gives you most information, and abstracts away lots of details. sysfs may be viewed as more correct that /proc/partitions and doesn't require hal to be running.
For a desktop program I would go for hal. On an embedded system I'd go with sysfs.
import os
def main():
dev = os.stat("/home/").st_dev
major, minor = os.major(dev), os.minor(dev)
print "/proc/partitions says:", ask_proc_partitions(major, minor)
print "HAL says:", ask_hal(major, minor)
print "/sys says:", ask_sysfs(major, minor)
def _parse_proc_partitions():
res = {}
for line in file("/proc/partitions"):
fields = line.split()
try:
tmaj = int(fields[0])
tmin = int(fields[1])
name = fields[3]
res[(tmaj, tmin)] = name
except:
# just ignore parse errors in header/separator lines
pass
return res
def ask_proc_partitions(major, minor):
d = _parse_proc_partitions()
return d[(major, minor)]
def ask_hal(major, minor):
import dbus
bus = dbus.SystemBus()
halobj = bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
hal = dbus.Interface(halobj, 'org.freedesktop.Hal.Manager')
def getdevprops(p):
bdevi = dbus.Interface(bus.get_object('org.freedesktop.Hal', p),
"org.freedesktop.Hal.Device")
return bdevi.GetAllProperties()
bdevs = hal.FindDeviceByCapability("block")
for bdev in bdevs:
props = getdevprops(bdev)
if (props['block.major'], props['block.minor']) == (major, minor):
parentprops = getdevprops(props['info.parent'])
return (str(props['block.device']),
str(parentprops['block.device']))
def ask_sysfs(major, minor):
from glob import glob
needle = "%d:%d" % (major, minor)
files = glob("/sys/class/block/*/dev")
for f in files:
if file(f).read().strip() == needle:
return os.path.dirname(f)
return None
if __name__ == '__main__':
main()
It looks like this post has some of your answer (still not sure just how to grab the major/minor out of the /dev/sda2 entry to match it up with what os.stat() returns for /:
Device number in stat command output
>>> import os
>>> print hex(os.stat('/')[2])
0x802
\ \minor device number
\major device number
[me#server /]$ ls -l /dev/sda2
brw-rw---- 1 root disk 8, 2 Jun 24 2004 /dev/sda2
[me#server jgaines2]$ \ \minor device number
\major device number
I recently had a need for this solution also. After seeing all the convoluted methods of getting the result I wanted through pure python, I decided to turn to the shell for help.
import subprocess
device = subprocess.check_output("grep '/filesystem' /proc/mounts | awk '{printf $1}'", shell=True)
print device
This gives me exactly what I want, the device string for where my filesystem is mounted.
Short, sweet, and runs in python. :)
There are problems with quite a few of the above solutions. There's actually a problem with the question as well.
The last answer (searching /proc/mounts) just doesn't work: searching for "/" will match every line in /proc/mounts. Even correcting this like this won't work:
import subprocess
device = subprocess.check_output("awk '$2 == \"/filesystem\" { print $1}' /proc/mounts", shell=True)
print device
When "/filesystem" is "/" you'll typically get two entries, one for "rootfs" and one for the actual device. It also won't work when the mounted file system name has spaces in it (the space appears as \040 in /proc/mounts).
The problem is made worse with btrfs subvolumes. Each subvolume is mounted separately but they all share the same device. If you're trying to use a btrfs snapshot for backups (as I was) then you need the subvolume name and an indication of the filesystem type.
This function returns a tuple of (device, mountpoint, filesystem) and seems to work:
import os
def get_filesystem_partition(fs):
res = None
dev = os.lstat(fs).st_dev
for line in file('/proc/mounts'):
# lines are device, mountpoint, filesystem, <rest>
# later entries override earlier ones
line = [s.decode('string_escape') for s in line.split()[:3]]
if dev == os.lstat(line[1]).st_dev:
res = tuple(line)
return res
That seems to work for all the cases I can think of, although I expect that there are still pathological cases where it falls to bits.
It is not the purdiest, but this will get you started:
#!/usr/bin/python
import os, stat, subprocess, shlex, re, sys
dev=os.stat('/')[stat.ST_DEV]
major=os.major(dev)
minor=os.minor(dev)
out = subprocess.Popen(shlex.split("df /"), stdout=subprocess.PIPE).communicate()
m=re.search(r'(/[^\s]+)\s',str(out))
if m:
mp= m.group(1)
else:
print "cannot parse df"
sys.exit(2)
print "'/' mounted at '%s' with dev number %i, %i" % (mp,major,minor)
On OS X:
'/' mounted at '/dev/disk0s2' with dev number 14, 2
On Ubuntu:
'/' mounted at '/dev/sda1' with dev number 8, 1
To get the device name, chop off the minor number from the partition name. On OS X, also chop the 's' + minor number.
How about using the (linux) blkid command (/sbin/blkid)
$ uname --kernel-name --kernel-release
Linux 3.2.0-4-amd64
$ python --version
Python 2.7.3
-
#!/usr/bin/env python
import subprocess
sys_command = "/sbin/blkid"
proc = subprocess.Popen(sys_command,
stdout=subprocess.PIPE,
shell=True)
# proc.communicate() returns a tuple (stdout,stderr)
blkid_output = proc.communicate()[0]
print blkid_output
Here's the output on a dual-boot laptop with an (unmounted) USB drive (sdb1)
$ ./blkid.py
/dev/sda1: LABEL="RECOVERY" UUID="xxxx-xxxx" TYPE="vfat"
/dev/sda2: LABEL="OS" UUID="xxxxxxxxxxxxxxx" TYPE="ntfs"
/dev/sda5: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="ext4"
/dev/sda6: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="swap"
/dev/sda7: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="ext4"
/dev/sdb1: LABEL="CrunchBang" TYPE="iso9660"
Here is how you can simply get the devices major and minor numbers:
import os
major, minor = divmod(os.stat('/').st_dev, 256)
I'm getting an error in a program that is supposed to run for a long time that too many files are open. Is there any way I can keep track of which files are open so I can print that list out occasionally and see where the problem is?
To list all open files in a cross-platform manner, I would recommend psutil.
#!/usr/bin/env python
import psutil
for proc in psutil.process_iter():
print(proc.open_files())
The original question implicitly restricts the operation to the currently running process, which can be accessed through psutil's Process class.
proc = psutil.Process()
print(proc.open_files())
Lastly, you'll want to run the code using an account with the appropriate permissions to access this information or you may see AccessDenied errors.
I ended up wrapping the built-in file object at the entry point of my program. I found out that I wasn't closing my loggers.
import io
import sys
import builtins
import traceback
from functools import wraps
def opener(old_open):
#wraps(old_open)
def tracking_open(*args, **kw):
file = old_open(*args, **kw)
old_close = file.close
#wraps(old_close)
def close():
old_close()
open_files.remove(file)
file.close = close
file.stack = traceback.extract_stack()
open_files.add(file)
return file
return tracking_open
def print_open_files():
print(f'### {len(open_files)} OPEN FILES: [{", ".join(f.name for f in open_files)}]', file=sys.stderr)
for file in open_files:
print(f'Open file {file.name}:\n{"".join(traceback.format_list(file.stack))}', file=sys.stderr)
open_files = set()
io.open = opener(io.open)
builtins.open = opener(builtins.open)
On Linux, you can look at the contents of /proc/self/fd:
$ ls -l /proc/self/fd/
total 0
lrwx------ 1 foo users 64 Jan 7 15:15 0 -> /dev/pts/3
lrwx------ 1 foo users 64 Jan 7 15:15 1 -> /dev/pts/3
lrwx------ 1 foo users 64 Jan 7 15:15 2 -> /dev/pts/3
lr-x------ 1 foo users 64 Jan 7 15:15 3 -> /proc/9527/fd
Although the solutions above that wrap opens are useful for one's own code, I was debugging my client to a third party library including some c extension code, so I needed a more direct way. The following routine works under darwin, and (I hope) other unix-like environments:
def get_open_fds():
'''
return the number of open file descriptors for current process
.. warning: will only work on UNIX-like os-es.
'''
import subprocess
import os
pid = os.getpid()
procs = subprocess.check_output(
[ "lsof", '-w', '-Ff', "-p", str( pid ) ] )
nprocs = len(
filter(
lambda s: s and s[ 0 ] == 'f' and s[1: ].isdigit(),
procs.split( '\n' ) )
)
return nprocs
If anyone can extend to be portable to windows, I'd be grateful.
On Linux, you can use lsof to show all files opened by a process.
As said earlier, you can list fds on Linux in /proc/self/fd, here is a simple method to list them programmatically:
import os
import sys
import errno
def list_fds():
"""List process currently open FDs and their target """
if not sys.platform.startswith('linux'):
raise NotImplementedError('Unsupported platform: %s' % sys.platform)
ret = {}
base = '/proc/self/fd'
for num in os.listdir(base):
path = None
try:
path = os.readlink(os.path.join(base, num))
except OSError as err:
# Last FD is always the "listdir" one (which may be closed)
if err.errno != errno.ENOENT:
raise
ret[int(num)] = path
return ret
On Windows, you can use Process Explorer to show all file handles owned by a process.
There are some limitations to the accepted response, in that it does not seem to count pipes. I had a python script that opened many sub-processes, and was failing to properly close standard input, output, and error pipes, which were used for communication. If I use the accepted response, it will fail to count these open pipes as open files, but (at least in Linux) they are open files and count toward the open file limit. The lsof -p solution suggested by sumid and shunc works in this situation, because it also shows you the open pipes.
Get a list of all open files. handle.exe is part of Microsoft's Sysinternals Suite. An alternative is the psutil Python module, but I find 'handle' will print out more files in use.
Here is what I made. Kludgy code warning.
#!/bin/python3
# coding: utf-8
"""Build set of files that are in-use by processes.
Requires 'handle.exe' from Microsoft SysInternals Suite.
This seems to give a more complete list than using the psutil module.
"""
from collections import OrderedDict
import os
import re
import subprocess
# Path to handle executable
handle = "E:/Installers and ZIPs/Utility/Sysinternalssuite/handle.exe"
# Get output string from 'handle'
handle_str = subprocess.check_output([handle]).decode(encoding='ASCII')
""" Build list of lists.
1. Split string output, using '-' * 78 as section breaks.
2. Ignore first section, because it is executable version info.
3. Turn list of strings into a list of lists, ignoring first item (it's empty).
"""
work_list = [x.splitlines()[1:] for x in handle_str.split(sep='-' * 78)[1:]]
""" Build OrderedDict of pid information.
pid_dict['pid_num'] = ['pid_name','open_file_1','open_file_2', ...]
"""
pid_dict = OrderedDict()
re1 = re.compile("(.*?\.exe) pid: ([0-9]+)") # pid name, pid number
re2 = re.compile(".*File.*\s\s\s(.*)") # File name
for x_list in work_list:
key = ''
file_values = []
m1 = re1.match(x_list[0])
if m1:
key = m1.group(2)
# file_values.append(m1.group(1)) # pid name first item in list
for y_strings in x_list:
m2 = re2.match(y_strings)
if m2:
file_values.append(m2.group(1))
pid_dict[key] = file_values
# Make a set of all the open files
values = []
for v in pid_dict.values():
values.extend(v)
files_open = sorted(set(values))
txt_file = os.path.join(os.getenv('TEMP'), 'lsof_handle_files')
with open(txt_file, 'w') as fd:
for a in sorted(files_open):
fd.write(a + '\n')
subprocess.call(['notepad', txt_file])
os.remove(txt_file)
I'd guess that you are leaking file descriptors. You probably want to look through your code to make sure that you are closing all of the files that you open.
You can use the following script. It builds on Claudiu's answer. It addresses some of the issues and adds additional features:
Prints a stack trace of where the file was opened
Prints on program exit
Keyword argument support
Here's the code and a link to the gist, which is possibly more up to date.
"""
Collect stacktraces of where files are opened, and prints them out before the
program exits.
Example
========
monitor.py
----------
from filemonitor import FileMonitor
FileMonitor().patch()
f = open('/bin/ls')
# end of monitor.py
$ python monitor.py
----------------------------------------------------------------------------
path = /bin/ls
> File "monitor.py", line 3, in <module>
> f = open('/bin/ls')
----------------------------------------------------------------------------
Solution modified from:
https://stackoverflow.com/questions/2023608/check-what-files-are-open-in-python
"""
from __future__ import print_function
import __builtin__
import traceback
import atexit
import textwrap
class FileMonitor(object):
def __init__(self, print_only_open=True):
self.openfiles = []
self.oldfile = __builtin__.file
self.oldopen = __builtin__.open
self.do_print_only_open = print_only_open
self.in_use = False
class File(self.oldfile):
def __init__(this, *args, **kwargs):
path = args[0]
self.oldfile.__init__(this, *args, **kwargs)
if self.in_use:
return
self.in_use = True
self.openfiles.append((this, path, this._stack_trace()))
self.in_use = False
def close(this):
self.oldfile.close(this)
def _stack_trace(this):
try:
raise RuntimeError()
except RuntimeError as e:
stack = traceback.extract_stack()[:-2]
return traceback.format_list(stack)
self.File = File
def patch(self):
__builtin__.file = self.File
__builtin__.open = self.File
atexit.register(self.exit_handler)
def unpatch(self):
__builtin__.file = self.oldfile
__builtin__.open = self.oldopen
def exit_handler(self):
indent = ' > '
terminal_width = 80
for file, path, trace in self.openfiles:
if file.closed and self.do_print_only_open:
continue
print("-" * terminal_width)
print(" {} = {}".format('path', path))
lines = ''.join(trace).splitlines()
_updated_lines = []
for l in lines:
ul = textwrap.fill(l,
initial_indent=indent,
subsequent_indent=indent,
width=terminal_width)
_updated_lines.append(ul)
lines = _updated_lines
print('\n'.join(lines))
print("-" * terminal_width)
print()
I'm trying to make a basic Windows application that builds a string out of user input and then adds it to the clipboard. How do I copy a string to the clipboard using Python?
Actually, pywin32 and ctypes seem to be an overkill for this simple task. tkinter is a cross-platform GUI framework, which ships with Python by default and has clipboard accessing methods along with other cool stuff.
If all you need is to put some text to system clipboard, this will do it:
from tkinter import Tk # in Python 2, use "Tkinter" instead
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append('i can has clipboardz?')
r.update() # now it stays on the clipboard after the window is closed
r.destroy()
And that's all, no need to mess around with platform-specific third-party libraries.
If you are using Python 2, replace tkinter with Tkinter.
I didn't have a solution, just a workaround.
Windows Vista onwards has an inbuilt command called clip that takes the output of a command from command line and puts it into the clipboard. For example, ipconfig | clip.
So I made a function with the os module which takes a string and adds it to the clipboard using the inbuilt Windows solution.
import os
def addToClipBoard(text):
command = 'echo ' + text.strip() + '| clip'
os.system(command)
# Example
addToClipBoard('penny lane')
# Penny Lane is now in your ears, eyes, and clipboard.
As previously noted in the comments however, one downside to this approach is that the echo command automatically adds a newline to the end of your text. To avoid this you can use a modified version of the command:
def addToClipBoard(text):
command = 'echo | set /p nul=' + text.strip() + '| clip'
os.system(command)
If you are using Windows XP it will work just following the steps in Copy and paste from Windows XP Pro's command prompt straight to the Clipboard.
You can use pyperclip - cross-platform clipboard module. Or Xerox - similar module, except requires the win32 Python module to work on Windows.
The simplest way is with pyperclip. Works in python 2 and 3.
To install this library, use:
pip install pyperclip
Example usage:
import pyperclip
pyperclip.copy("your string")
If you want to get the contents of the clipboard:
clipboard_content = pyperclip.paste()
You can use the excellent pandas, which has a built in clipboard support, but you need to pass through a DataFrame.
import pandas as pd
df=pd.DataFrame(['Text to copy'])
df.to_clipboard(index=False,header=False)
You can also use ctypes to tap into the Windows API and avoid the massive pywin32 package. This is what I use (excuse the poor style, but the idea is there):
import ctypes
# Get required functions, strcpy..
strcpy = ctypes.cdll.msvcrt.strcpy
ocb = ctypes.windll.user32.OpenClipboard # Basic clipboard functions
ecb = ctypes.windll.user32.EmptyClipboard
gcd = ctypes.windll.user32.GetClipboardData
scd = ctypes.windll.user32.SetClipboardData
ccb = ctypes.windll.user32.CloseClipboard
ga = ctypes.windll.kernel32.GlobalAlloc # Global memory allocation
gl = ctypes.windll.kernel32.GlobalLock # Global memory Locking
gul = ctypes.windll.kernel32.GlobalUnlock
GMEM_DDESHARE = 0x2000
def Get():
ocb(None) # Open Clip, Default task
pcontents = gcd(1) # 1 means CF_TEXT.. too lazy to get the token thingy...
data = ctypes.c_char_p(pcontents).value
#gul(pcontents) ?
ccb()
return data
def Paste(data):
ocb(None) # Open Clip, Default task
ecb()
hCd = ga(GMEM_DDESHARE, len(bytes(data,"ascii")) + 1)
pchData = gl(hCd)
strcpy(ctypes.c_char_p(pchData), bytes(data, "ascii"))
gul(hCd)
scd(1, hCd)
ccb()
Here's the most easy and reliable way I found if you're okay depending on Pandas. However I don't think this is officially part of the Pandas API so it may break with future updates. It works as of 0.25.3
from pandas.io import clipboard
clipboard.copy("test")
For some reason I've never been able to get the Tk solution to work for me. kapace's solution is much more workable, but the formatting is contrary to my style and it doesn't work with Unicode. Here's a modified version.
import ctypes
from ctypes.wintypes import BOOL, HWND, HANDLE, HGLOBAL, UINT, LPVOID
from ctypes import c_size_t as SIZE_T
OpenClipboard = ctypes.windll.user32.OpenClipboard
OpenClipboard.argtypes = HWND,
OpenClipboard.restype = BOOL
EmptyClipboard = ctypes.windll.user32.EmptyClipboard
EmptyClipboard.restype = BOOL
GetClipboardData = ctypes.windll.user32.GetClipboardData
GetClipboardData.argtypes = UINT,
GetClipboardData.restype = HANDLE
SetClipboardData = ctypes.windll.user32.SetClipboardData
SetClipboardData.argtypes = UINT, HANDLE
SetClipboardData.restype = HANDLE
CloseClipboard = ctypes.windll.user32.CloseClipboard
CloseClipboard.restype = BOOL
CF_UNICODETEXT = 13
GlobalAlloc = ctypes.windll.kernel32.GlobalAlloc
GlobalAlloc.argtypes = UINT, SIZE_T
GlobalAlloc.restype = HGLOBAL
GlobalLock = ctypes.windll.kernel32.GlobalLock
GlobalLock.argtypes = HGLOBAL,
GlobalLock.restype = LPVOID
GlobalUnlock = ctypes.windll.kernel32.GlobalUnlock
GlobalUnlock.argtypes = HGLOBAL,
GlobalSize = ctypes.windll.kernel32.GlobalSize
GlobalSize.argtypes = HGLOBAL,
GlobalSize.restype = SIZE_T
GMEM_MOVEABLE = 0x0002
GMEM_ZEROINIT = 0x0040
unicode_type = type(u'')
def get():
text = None
OpenClipboard(None)
handle = GetClipboardData(CF_UNICODETEXT)
pcontents = GlobalLock(handle)
size = GlobalSize(handle)
if pcontents and size:
raw_data = ctypes.create_string_buffer(size)
ctypes.memmove(raw_data, pcontents, size)
text = raw_data.raw.decode('utf-16le').rstrip(u'\0')
GlobalUnlock(handle)
CloseClipboard()
return text
def put(s):
if not isinstance(s, unicode_type):
s = s.decode('mbcs')
data = s.encode('utf-16le')
OpenClipboard(None)
EmptyClipboard()
handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, len(data) + 2)
pcontents = GlobalLock(handle)
ctypes.memmove(pcontents, data, len(data))
GlobalUnlock(handle)
SetClipboardData(CF_UNICODETEXT, handle)
CloseClipboard()
paste = get
copy = put
The above has changed since this answer was first created, to better cope with extended Unicode characters and Python 3. It has been tested in both Python 2.7 and 3.5, and works even with emoji such as \U0001f601 (😁).
Update 2021-10-26: This was working great for me in Windows 7 and Python 3.8. Then I got a new computer with Windows 10 and Python 3.10, and it failed for me the same way as indicated in the comments. This post gave me the answer. The functions from ctypes don't have argument and return types properly specified, and the defaults don't work consistently with 64-bit values. I've modified the above code to include that missing information.
I've tried various solutions, but this is the simplest one that passes my test:
#coding=utf-8
import win32clipboard # http://sourceforge.net/projects/pywin32/
def copy(text):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(text, win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
def paste():
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
return data
if __name__ == "__main__":
text = "Testing\nthe “clip—board”: 📋"
try: text = text.decode('utf8') # Python 2 needs decode to make a Unicode string.
except AttributeError: pass
print("%r" % text.encode('utf8'))
copy(text)
data = paste()
print("%r" % data.encode('utf8'))
print("OK" if text == data else "FAIL")
try: print(data)
except UnicodeEncodeError as er:
print(er)
print(data.encode('utf8'))
Tested OK in Python 3.4 on Windows 8.1 and Python 2.7 on Windows 7. Also when reading Unicode data with Unix linefeeds copied from Windows. Copied data stays on the clipboard after Python exits: "Testing
the “clip—board”: 📋"
If you want no external dependencies, use this code (now part of cross-platform pyperclip - C:\Python34\Scripts\pip install --upgrade pyperclip):
def copy(text):
GMEM_DDESHARE = 0x2000
CF_UNICODETEXT = 13
d = ctypes.windll # cdll expects 4 more bytes in user32.OpenClipboard(None)
try: # Python 2
if not isinstance(text, unicode):
text = text.decode('mbcs')
except NameError:
if not isinstance(text, str):
text = text.decode('mbcs')
d.user32.OpenClipboard(0)
d.user32.EmptyClipboard()
hCd = d.kernel32.GlobalAlloc(GMEM_DDESHARE, len(text.encode('utf-16-le')) + 2)
pchData = d.kernel32.GlobalLock(hCd)
ctypes.cdll.msvcrt.wcscpy(ctypes.c_wchar_p(pchData), text)
d.kernel32.GlobalUnlock(hCd)
d.user32.SetClipboardData(CF_UNICODETEXT, hCd)
d.user32.CloseClipboard()
def paste():
CF_UNICODETEXT = 13
d = ctypes.windll
d.user32.OpenClipboard(0)
handle = d.user32.GetClipboardData(CF_UNICODETEXT)
text = ctypes.c_wchar_p(handle).value
d.user32.CloseClipboard()
return text
Use pyperclip module
Install using pip pip install pyperclip.
https://pypi.org/project/pyperclip/
Copy text "Hello World!" to clip board
import pyperclip
pyperclip.copy('Hello World!')
You can use Ctrl+V anywhere to paste this somewhere.
Paste the copied text using python
pyperclip.paste() # This returns the copied text of type <class 'str'>
If you don't like the name you can use the derivative module clipboard.
Note: It's just a selective wrapper of pyperclip
After installing, import it:
import clipboard
Then you can copy like this:
clipboard.copy("This is copied")
You can also paste the copied text:
clipboard.paste()
Looks like you need to add win32clipboard to your site-packages. It's part of the pywin32 package
Not all of the answers worked for my various python configurations so this solution only uses the subprocess module. However, copy_keyword has to be pbcopy for Mac or clip for Windows:
import subprocess
subprocess.run('copy_keyword', universal_newlines=True, input='New Clipboard Value 😀')
Here's some more extensive code that automatically checks what the current operating system is:
import platform
import subprocess
copy_string = 'New Clipboard Value 😀'
# Check which operating system is running to get the correct copying keyword.
if platform.system() == 'Darwin':
copy_keyword = 'pbcopy'
elif platform.system() == 'Windows':
copy_keyword = 'clip'
subprocess.run(copy_keyword, universal_newlines=True, input=copy_string)
I think there is a much simpler solution to this.
name = input('What is your name? ')
print('Hello %s' % (name) )
Then run your program in the command line
python greeter.py | clip
This will pipe the output of your file to the clipboard
Widgets also have method named .clipboard_get() that returns the contents of the clipboard (unless some kind of error happens based on the type of data in the clipboard).
The clipboard_get() method is mentioned in this bug report:
http://bugs.python.org/issue14777
Strangely, this method was not mentioned in the common (but unofficial) online TkInter documentation sources that I usually refer to.
Solution with stdlib, without security issues
The following solution works in Linux without any additional library and without the risk of executing unwanted code in your shell.
import subprocess
def to_clipboard(text: str) -> None:
sp = subprocess.Popen(["xclip"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
sp.communicate(text.encode("utf8"))
Note that there multiple clipboard in Linux, the you use with the Middle Mouse (Primary) and yet another that you use pressing STRG+C,STRG+V.
You can define which clipboard is used by adding a selection parameter i.e. ["xclip", "-selection", "clipboard"].
See the man xclip for details.
If you using Windows, just replace xclip with clip.
This solution works without Tkinter, which not available some Python installations (i.e. the custom build I am currently using).
In addition to Mark Ransom's answer using ctypes:
This does not work for (all?) x64 systems since the handles seem to be truncated to int-size.
Explicitly defining args and return values helps to overcomes this problem.
import ctypes
import ctypes.wintypes as w
CF_UNICODETEXT = 13
u32 = ctypes.WinDLL('user32')
k32 = ctypes.WinDLL('kernel32')
OpenClipboard = u32.OpenClipboard
OpenClipboard.argtypes = w.HWND,
OpenClipboard.restype = w.BOOL
GetClipboardData = u32.GetClipboardData
GetClipboardData.argtypes = w.UINT,
GetClipboardData.restype = w.HANDLE
EmptyClipboard = u32.EmptyClipboard
EmptyClipboard.restype = w.BOOL
SetClipboardData = u32.SetClipboardData
SetClipboardData.argtypes = w.UINT, w.HANDLE,
SetClipboardData.restype = w.HANDLE
CloseClipboard = u32.CloseClipboard
CloseClipboard.argtypes = None
CloseClipboard.restype = w.BOOL
GHND = 0x0042
GlobalAlloc = k32.GlobalAlloc
GlobalAlloc.argtypes = w.UINT, w.ctypes.c_size_t,
GlobalAlloc.restype = w.HGLOBAL
GlobalLock = k32.GlobalLock
GlobalLock.argtypes = w.HGLOBAL,
GlobalLock.restype = w.LPVOID
GlobalUnlock = k32.GlobalUnlock
GlobalUnlock.argtypes = w.HGLOBAL,
GlobalUnlock.restype = w.BOOL
GlobalSize = k32.GlobalSize
GlobalSize.argtypes = w.HGLOBAL,
GlobalSize.restype = w.ctypes.c_size_t
unicode_type = type(u'')
def get():
text = None
OpenClipboard(None)
handle = GetClipboardData(CF_UNICODETEXT)
pcontents = GlobalLock(handle)
size = GlobalSize(handle)
if pcontents and size:
raw_data = ctypes.create_string_buffer(size)
ctypes.memmove(raw_data, pcontents, size)
text = raw_data.raw.decode('utf-16le').rstrip(u'\0')
GlobalUnlock(handle)
CloseClipboard()
return text
def put(s):
if not isinstance(s, unicode_type):
s = s.decode('mbcs')
data = s.encode('utf-16le')
OpenClipboard(None)
EmptyClipboard()
handle = GlobalAlloc(GHND, len(data) + 2)
pcontents = GlobalLock(handle)
ctypes.memmove(pcontents, data, len(data))
GlobalUnlock(handle)
SetClipboardData(CF_UNICODETEXT, handle)
CloseClipboard()
#Test run
paste = get
copy = put
copy("Hello World!")
print(paste())
also you can use > clipboard
import clipboard
def copy(txt):
clipboard.copy(txt)
copy("your txt")
If (and only if) the application already uses Qt, you can use this (with the advantage of no additional third party dependency)
from PyQt5.QtWidgets import QApplication
clipboard = QApplication.clipboard()
# get text (if there's text inside instead of e.g. file)
clipboard.text()
# set text
clipboard.setText(s)
This requires a Qt application object to be already constructed, so it should not be used unless the application already uses Qt.
Besides, as usual, in X systems (and maybe other systems too), the content only persist until the application exists unless you use something like parcellite or xclipboard.
Documentation:
QGuiApplication Class | Qt GUI 5.15.6
QClipboard Class | Qt GUI 5.15.6
See also: python - PyQT - copy file to clipboard - Stack Overflow
import wx
def ctc(text):
if not wx.TheClipboard.IsOpened():
wx.TheClipboard.Open()
data = wx.TextDataObject()
data.SetText(text)
wx.TheClipboard.SetData(data)
wx.TheClipboard.Close()
ctc(text)
The snippet I share here take advantage of the ability to format text files: what if you want to copy a complex output to the clipboard ? (Say a numpy array in column or a list of something)
import subprocess
import os
def cp2clip(clist):
#create a temporary file
fi=open("thisTextfileShouldNotExist.txt","w")
#write in the text file the way you want your data to be
for m in clist:
fi.write(m+"\n")
#close the file
fi.close()
#send "clip < file" to the shell
cmd="clip < thisTextfileShouldNotExist.txt"
w = subprocess.check_call(cmd,shell=True)
#delete the temporary text file
os.remove("thisTextfileShouldNotExist.txt")
return w
works only for windows, can be adapted for linux or mac I guess. Maybe a bit complicated...
example:
>>>cp2clip(["ET","phone","home"])
>>>0
Ctrl+V in any text editor :
ET
phone
home
This is the improved answer of atomizer.
Note 2 calls of update() and 200 ms delay between them. They protect freezing applications due to an unstable state of the clipboard:
from Tkinter import Tk
import time
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append('some string')
r.update()
time.sleep(.2)
r.update()
r.destroy()
Use python's clipboard library!
import clipboard as cp
cp.copy("abc")
Clipboard contains 'abc' now. Happy pasting!
You can use winclip32 module!
install:
pip install winclip32
to copy:
import winclip32
winclip32.set_clipboard_data(winclip32.UNICODE_STD_TEXT, "some text")
to get:
import winclip32
print(winclip32.get_clipboard_data(winclip32.UNICODE_STD_TEXT))
for more informations: https://pypi.org/project/winclip32/
On Windows, you can use this. No external dependencies neither have to open sub-process:
import win32clipboard
def to_clipboard(txt):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(txt)
win32clipboard.CloseClipboard()
My multiplatform solution base on this question:
import subprocess
import distutils.spawn
def clipit(text):
if distutils.spawn.find_executable("xclip"):
# for Linux
subprocess.run(["xclip", "-i"], input=text.encode("utf8"))
elif distutils.spawn.find_executable("xsel"):
# for Linux
subprocess.run(["xsel", "--input"], input=text.encode("utf8"))
elif distutils.spawn.find_executable("clip"):
# for Windows
subprocess.run(["clip"], input=text.encode("utf8"))
else:
import pyperclip
print("I use module pyperclip.")
pyperclip.copy(text)
Code snippet to copy the clipboard:
Create a wrapper Python code in a module named (clipboard.py):
import clr
clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import Clipboard
def setText(text):
Clipboard.SetText(text)
def getText():
return Clipboard.GetText()
Then import the above module into your code.
import io
import clipboard
code = clipboard.getText()
print code
code = "abcd"
clipboard.setText(code)
I must give credit to the blog post Clipboard Access in IronPython.
you can try this:
command = 'echo content |clip'
subprocess.check_call(command, shell=True)