How do I read text from the (windows) clipboard with python?
You can use the module called win32clipboard, which is part of pywin32.
Here is an example that first sets the clipboard data then gets it:
import win32clipboard
# set clipboard data
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText('testing 123')
win32clipboard.CloseClipboard()
# get clipboard data
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
print data
An important reminder from the documentation:
When the window has finished examining or changing the clipboard,
close the clipboard by calling CloseClipboard. This enables other
windows to access the clipboard. Do not place an object on the
clipboard after calling CloseClipboard.
you can easily get this done through the built-in module Tkinter which is basically a GUI library. This code creates a blank widget to get the clipboard content from OS.
from tkinter import Tk # Python 3
#from Tkinter import Tk # for Python 2.x
Tk().clipboard_get()
I found pyperclip to be the easiest way to get access to the clipboard from python:
Install pyperclip:
pip install pyperclip
Usage:
import pyperclip
s = pyperclip.paste()
pyperclip.copy(s)
# the type of s is string
With supports Windows, Linux and Mac, and seems to work with non-ASCII characters, too.
Tested characters include ±°©©αβγθΔΨΦåäö
If you don't want to install extra packages, ctypes can get the job done as well.
import ctypes
CF_TEXT = 1
kernel32 = ctypes.windll.kernel32
kernel32.GlobalLock.argtypes = [ctypes.c_void_p]
kernel32.GlobalLock.restype = ctypes.c_void_p
kernel32.GlobalUnlock.argtypes = [ctypes.c_void_p]
user32 = ctypes.windll.user32
user32.GetClipboardData.restype = ctypes.c_void_p
def get_clipboard_text():
user32.OpenClipboard(0)
try:
if user32.IsClipboardFormatAvailable(CF_TEXT):
data = user32.GetClipboardData(CF_TEXT)
data_locked = kernel32.GlobalLock(data)
text = ctypes.c_char_p(data_locked)
value = text.value
kernel32.GlobalUnlock(data_locked)
return value
finally:
user32.CloseClipboard()
print(get_clipboard_text())
I've seen many suggestions to use the win32 module, but Tkinter provides the shortest and easiest method I've seen, as in this post: How do I copy a string to the clipboard on Windows using Python?
Plus, Tkinter is in the python standard library.
The most upvoted answer above is weird in a way that it simply clears the Clipboard and then gets the content (which is then empty). One could clear the clipboard to be sure that some clipboard content type like "formated text" does not "cover" your plain text content you want to save in the clipboard.
The following piece of code replaces all newlines in the clipboard by spaces, then removes all double spaces and finally saves the content back to the clipboard:
import win32clipboard
win32clipboard.OpenClipboard()
c = win32clipboard.GetClipboardData()
win32clipboard.EmptyClipboard()
c = c.replace('\n', ' ')
c = c.replace('\r', ' ')
while c.find(' ') != -1:
c = c.replace(' ', ' ')
win32clipboard.SetClipboardText(c)
win32clipboard.CloseClipboard()
The python standard library does it...
try:
# Python3
import tkinter as tk
except ImportError:
# Python2
import Tkinter as tk
def getClipboardText():
root = tk.Tk()
# keep the window from showing
root.withdraw()
return root.clipboard_get()
For my console program the answers with tkinter above did not quite work for me because the .destroy() always gave an error,:
can't invoke "event" command: application has been destroyed while executing...
or when using .withdraw() the console window did not get the focus back.
To solve this you also have to call .update() before the .destroy(). Example:
# Python 3
import tkinter
r = tkinter.Tk()
text = r.clipboard_get()
r.withdraw()
r.update()
r.destroy()
The r.withdraw() prevents the frame from showing for a milisecond, and then it will be destroyed giving the focus back to the console.
Use Pythons library Clipboard
Its simply used like this:
import clipboard
clipboard.copy("this text is now in the clipboard")
print clipboard.paste()
Try win32clipboard from the win32all package (that's probably installed if you're on ActiveState Python).
See sample here: http://code.activestate.com/recipes/474121/
After whole 12 years, I have a solution and you can use it without installing any package.
from tkinter import Tk, TclError
from time import sleep
while True:
try:
clipboard = Tk().clipboard_get()
print(clipboard)
sleep(5)
except TclError:
print("Clipboard is empty.")
sleep(5)
import pandas as pd
df = pd.read_clipboard()
A not very direct trick:
Use pyautogui hotkey:
Import pyautogui
pyautogui.hotkey('ctrl', 'v')
Therefore, you can paste the clipboard data as you like.
Why not try calling powershell?
import subprocess
def getClipboard():
ret = subprocess.getoutput("powershell.exe -Command Get-Clipboard")
return ret
For users of Anaconda: distributions don't come with pyperclip, but they do come with pandas which redistributes pyperclip:
>>> from pandas.io.clipboard import clipboard_get, clipboard_set
>>> clipboard_get()
'from pandas.io.clipboard import clipboard_get, clipboard_set'
>>> clipboard_set("Hello clipboard!")
>>> clipboard_get()
'Hello clipboard!'
I find this easier to use than pywin32 (which is also included in distributions).
Related
I wrote a py file called simplifier. Usually when you double click the py file, Windows should give you both a console and the program. Just like the picture below.
However, I clicked my py file and the console showed up and disappeared in a flash and the program did not show up at all. Usually this means there should be some bugs in my code. So I opened the py file in IDLE and ran it, expecting the shell to give me an error. However, it did not report anything. I don't know how to locate the error. The file used to work well and it just started to behave like that. I tested putting "input('')" only in a py file and it worked as expected. And some of my programs also work well, but the rest doesn't.
Could the bug come from my imported modules? I import some module written by myself (ez and eztk). I checked those functions. They are ok.
Here is the code of simplifier.
from tkinter import *
from tkinter import messagebox
from eztk import *
import ez
root=Tk()
root['bg']='MintCream'
t1=Text(root)
def newline():
t=gettxt(t1)
new=''
for i,ch in enumerate(t):
if ch=='\n' and t[i+1:i+3]!='- ':
new+=' '
else:
new+=ch
inst2(new)
w0=Label(root,text='Input:↑')
w1=Button(root,text="\\n",command=newline)
def brackets():
t=gettxt(t1)
new=''
stop=0
d={'[':']','(':')','{':'}',0:None}
for ch in t:
if ch in d:
stop=ch
elif ch==d[stop]:
stop=0
elif not stop:
new+=ch
inst2(new)
w2=Button(root,text='([{}])',command=brackets)
def linecount(event):
count=lambda t:t.count('\n')+(t[-1]!='\n') if t else 0
up=count(gettxt(t1))
down=count(gettxt(t2))
w3['text']=f'LineCount:↑{up}↓{down}'
root.bind('<KeyPress>', linecount)
w3=Label(root,text='LineCount')
def clear():
deltxt(t1)
deltxt(t2)
w4=Button(root,text='Clear',command=clear)
t2=Text(root)
ws=[w0,w1,w2,w3,w4]
t1.grid(row=0,column=0,columnspan=len(ws))
for i,w in enumerate(ws):
w.configure(relief=FLAT,bg='SeaGreen1')
w.grid(row=1,column=i,sticky=NS)
t2.grid(row=2,column=0,columnspan=len(ws))
def inst2(text):
deltxt(t2)
instxt(t2,text)
linecount('<KeyPress>')
try: ez.cpc(text)
except UnicodeError: messagebox.showerror('Error','You need to copy it to your clipboard manually.')
root.mainloop()
These are the functions used in the imported modules:
def copyToClipboard(text):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(text)
win32clipboard.CloseClipboard()
## abbreviation
cpc=copyToClipboard
def gettxt(text):
return text.get(1.0,'end').strip()
def deltxt(text):
text.delete(1.0,'end')
def instxt(textwidget,text):
textwidget.insert(1.0,text)
--- Update ---
I just tried copy the 4 functions to the simplifier.py instead of importing them, it worked. However, I also tried importing either of them and both cases failed. And there is still no error after I ran them in the python shell. Actually the bottom 3 functions are the only code in my eztk module. And it still doesn't work as expected when I import eztk alone, which means there shouldn't be any problems with importing.
I'm trying to add to the "recently used" files list from Python 3 on Ubuntu.
I am able to successfully read the recently used file list like this:
from gi.repository import Gtk
recent_mgr = Gtk.RecentManager.get_default()
for item in recent_mgr.get_items():
print(item.get_uri())
This prints out the same list of files I see when I look at "Recent" in Nautilus, or look at the "Recently Used" place in the file dialog of apps like GIMP.
However, when I tried adding an item like this (where /home/laurence/foo/bar.txt is an existing text file)...
recent_mgr.add_item('file:///home/laurence/foo/bar.txt')
...the file does not show up in the Recent section of Nautilus or in file dialogs. It doesn't even show up in the results returned by get_items().
How can I add a file to GTK's recently used file list from Python?
A Gtk.RecentManager needs to emit the changed signal for the update to be written in a private attribute of the C++ class. To use a RecentManager object in an application, you need to start the event loop by calling Gtk.main:
from gi.repository import Gtk
recent_mgr = Gtk.RecentManager.get_default()
uri = r'file:/path/to/my/file'
recent_mgr.add_item(uri)
Gtk.main()
If you don't call Gtk.main(), the changed signal is not emitted and nothing happens.
To answer #andlabs query, the reason why RecentManager.add_item returns a boolean is because the g_file_query_info_async function is called. The callback function gtk_recent_manager_add_item_query_info then gathers the mimetype, application name and command into a GtkRecentData struct and finally calls gtk_recent_manager_add_full. The source is here.
If anything goes wrong, it is well after add_item has finished, so the method just returns True if the object it is called from is a RecentManager and if the uri is not NULL; and False otherwise.
The documentation is inaccurate in saying:
Returns TRUE if the new item was successfully added to the recently used resources list
as returning TRUE only means that an asynchronous function was called to deal with the addition of a new item.
As suggested by Laurence Gonsalves, the following runs pseudo-synchronously:
from gi.repository import Gtk, GObject
recent_mgr = Gtk.RecentManager.get_default()
uri = r'file:/path/to/my/file'
recent_mgr.add_item(uri)
GObject.idle_add(Gtk.main_quit)
Gtk.main()
This is my solution (complet script) with timer for quit GTK.main() loop
#!/usr/bin/env python3
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
import sys
import os
import subprocess
recent_mgr = Gtk.RecentManager.get_default()
if len(sys.argv) <= 1:
paths = (os.getcwd(),)
else:
paths = sys.argv[1:]
for path in paths:
if os.path.exists(path):
if path[0] != "/":
path = os.getcwd() + "/" + path
subprocess.call(["touch", "-a", path])
uri = r"file:" + path
recent_mgr.add_item(uri)
GLib.timeout_add(22, Gtk.main_quit, None)
Gtk.main()
Is it possible for python to accept input like this:
Folder name: Download
But instead of the user typing "Download" it is already there as a initial value. If the user wants to edit it as "Downloads" all he has to do is add a 's' and press enter.
Using normal input command:
folder=input('Folder name: ')
all I can get is a blank prompt:
Folder name:
Is there a simple way to do this that I'm missing?
The standard library functions input() and raw_input() don't have this functionality. If you're using Linux you can use the readline module to define an input function that uses a prefill value and advanced line editing:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt) # or raw_input in Python 2
finally:
readline.set_startup_hook()
I'm assuming you mean from the command-line. I've never seen initial values for command line prompts, they're usually of the form:
Folder [default] :
which in code is simply:
res = raw_input('Folder [default] : ')
res = res or 'default'
Alternatively, you can try to do something using the curses module in Python.
This works in windows.
import win32console
_stdin = win32console.GetStdHandle(win32console.STD_INPUT_HANDLE)
def input_def(prompt, default=''):
keys = []
for c in unicode(default):
evt = win32console.PyINPUT_RECORDType(win32console.KEY_EVENT)
evt.Char = c
evt.RepeatCount = 1
evt.KeyDown = True
keys.append(evt)
_stdin.WriteConsoleInput(keys)
return raw_input(prompt)
if __name__ == '__main__':
name = input_def('Folder name: ')
print
print name
I finally found a simple alternative that works on Windows and Linux. Essentially, i'm using the pyautogui module to simulate the user's input. in practice, it looks like this:
from pyautogui import typewrite
print("enter folder name: ")
typewrite("Default Value")
folder = input()
A Word of Warning:
Theoretically, the user can insert characters in the middle of the "default" input by pressing a key before typewrite finishes.
pyautogui is notoriously unreliable on headless systems, so make sure to provide a backup solution in case the import fails. If you run into No module named 'Xlib', try to install the python3-xlib or python-xlib package (or the xlib module). Running over ssh can also be a problem.
An example fallback implementation:
Since a missing X-server can logically only happen on linux, here's an implementation that uses sth's answer as fallback:
try:
from pyautogui import typewrite
autogui = True
except (ImportError, KeyError):
import readline
autogui = False
def rlinput(prompt, prefill=''):
if autogui:
print(prompt)
typewrite(prefill)
return input()
else:
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt)
finally:
readline.set_startup_hook()
I think that the best (the easiest and most portable) solution is a combination of #rlotun and #Stephen answers:
default = '/default/path/'
dir = raw_input('Folder [%s]' % default)
dir = dir or default
I would like to suggest using the clipboard to solve this problem. Paste the clipboard into the input line, edit as required, press enter. Variable clpstack is used to protect existing clipboard contents. This code is for Windows. Linux could use import clipboard.
import pyperclip as clp
clpstack=clp.paste()
clp.copy("192.168.4.1")
HOST = input("Enter telnet host: ")
clp.copy(clpstack)
I found PyInquirer to be very helpful, especially when building interactive console applications frequently. Prompting a user with a default modifiable value would look as follows:
from PyInquirer import prompt
question = [
{
'type': 'input',
'name': 'first_name',
'message': 'Name please',
'default': 'Max'
}
]
answer = prompt(question)
print('Hello {}'.format(answer['first_name']))
Recently faced this problem. None of the above answers seem to be flawless. So I did some research, and found the following solution to be the easiest, and works both for Windows and Linux:
import keyboard
def input_with_default(prompt_, default_):
keyboard.write(default_)
return input(prompt_)
if __name__ == "__main__":
print(input_with_default("Please enter: ", "hello world"))
I like this, It works on window
def inputWdefault(prompt, default):
bck = chr(8) * len(default)
ret = input(prompt + default + bck)
return ret or default
I liked the approach taken by #MCO so I refactored the code. I tested it on X Windows and Microsoft Windows 10 WSL 2 using Microsoft Terminal:
def input_with_default(prompt, prefill=''):
try:
from pyautogui import typewrite
print(prompt)
typewrite(prefill)
return input()
except (ImportError, KeyError):
import readline
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt)
finally:
readline.set_startup_hook()
Not the best aproach but for the sake of sharing...
You could use Javascript to get all sort of inputs in IPython Notebook.
from IPython.display import HTML
newvar = ""
htm = """
<input id="inptval" style="width:60%;" type="text" value="This is an editable default value.">
<button onclick="set_value()" style="width:20%;">OK</button>
<script type="text/Javascript">
function set_value(){
var input_value = document.getElementById('inptval').value;
var command = "newvar = '" + input_value + "'";
var kernel = IPython.notebook.kernel;
kernel.execute(command);
}
</script>
"""
HTML(htm)
On the next cell you can use the new variable:
print newvar
We can use Tkinter and use a StringVar to do this. The limitation is that the input is through a Tkinter window.
from tkinter import Tk, LEFT, BOTH, StringVar
from tkinter.ttk import Entry, Frame
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Entry")
self.pack(fill=BOTH, expand=1)
self.contents = StringVar()
# give the StringVar a default value
self.contents.set('test')
self.entry = Entry(self)
self.entry.pack(side=LEFT, padx=15)
self.entry["textvariable"] = self.contents
self.entry.bind('<Key-Return>', self.on_changed)
def on_changed(self, event):
print('contents: {}'.format(self.contents.get()))
return True
def main():
root = Tk()
ex = Example(root)
root.geometry("250x100+300+300")
root.mainloop()
if __name__ == '__main__':
main()
If you are writing a CLI, you might want to consider using the python-click library for this.
You would achieve your goal with the following code:
import click
user_input = click.prompt(text="Folder name", default="Download")
print(f"{user_input=}")
If you run this code, and type in nothing, then you get:
$ python3 cli_code.py
Folder name [Download]:
user_input='Download'
If you run this code, and type in 'my-dir', then you get:
$ python3 cli_code.py
Folder name [Download]: my-dir
user_input='my-dir'
Try using an "f-string" and "or" combination, say:
default_name = "that_folder"
this_folder = input(f"Folder name: ({default_name}) ") or default_name
print(this_folder)
If you hit Return without typing in the folder name, the default_name will be assumed.
This is not a very Good Answer but it is a work around for windows. As hard as I tried, I could not get Readline or pyReadline to work on my Windows10 computer with Python Ver 3.5. So I wrote this instead. Not the best code in the world since I've only been using Python for 3 months. But it works.
import os
def note_input(defaultvalue):
#Create a textfile
txtfile = open("txtfile.txt", "w")
#
# populate it with the default value
txtfile.write(defaultvalue)
txtfile.close()
#
# call Notepad
os.system("notepad.exe txtfile.txt")
# input("Just holding until notepad is close : ") (did not need this line)
#
# get the Value Entered/Changed in Notepad
txtfile = open("txtfile.txt", "r")
func_value = txtfile.read()
txtfile.close()
return func_value
# END DEF
Notepad stopped the program from running until it was closed, so the input() line below it was not needed. Once notepad was opened the first time and placed where I wanted it on the screen, It was like a popup input window. I assume you can use any text editor like Notepad++ or Scripe or Code Writer, etc.
If you do that, the user would have to delete the existing word. What about providing a default value if the user hits "return"?
>>> default_folder = "My Documents"
>>> try: folder = input("folder name [%s]:" %default_folder)
... except SyntaxError: folder = default_folder
I want my Python script to be able to copy and paste to/from the clipboard via x11 (so that it will work on Linux). Can anyone point me to specific resources I can look at, or the concepts I would have to master?
Is this possible to do with the Python X library at http://python-xlib.sourceforge.net ?
Tkinter-based solution mentioned in Cameron Laird's answer:
import Tkinter
root = Tkinter.Tk()
print(root.selection_get(selection="CLIPBOARD"))
Replace "CLIPBOARD" with "PRIMARY" to get PRIMARY selection instead.
Also see this answer.
python-xlib solution, based on PrintSelection() and python-xlib/examples/get_selection.py
from Xlib import X, display as Xdisplay
def property2str(display, prop):
if prop.property_type == display.get_atom("STRING"):
return prop.value.decode('ISO-8859-1')
elif prop.property_type == display.get_atom("UTF8_STRING"):
return prop.value.decode('UTF-8')
else:
return "".join(str(c) for c in prop.value)
def get_selection(display, window, bufname, typename):
bufid = display.get_atom(bufname)
typeid = display.get_atom(typename)
propid = display.get_atom('XSEL_DATA')
incrid = display.get_atom('INCR')
window.change_attributes(event_mask = X.PropertyChangeMask)
window.convert_selection(bufid, typeid, propid, X.CurrentTime)
while True:
ev = display.next_event()
if ev.type == X.SelectionNotify and ev.selection == bufid:
break
if ev.property == X.NONE:
return None # request failed, e.g. owner can't convert to target format type
else:
prop = window.get_property(propid, X.AnyPropertyType, 0, 2**31-1, 1)
if prop.property_type == incrid:
result = ""
while True:
while True:
ev = display.next_event()
if ev.type == X.PropertyNotify and ev.atom == propid and ev.state == X.PropertyNewValue:
break
prop = window.get_property(propid, X.AnyPropertyType, 0, 2**31-1, 1)
if len(prop.value) == 0:
break
result += property2str(display, prop)
return result
else:
return property2str(display, prop)
display = Xdisplay.Display()
window = display.screen().root.create_window(0,0, 1,1, 0, X.CopyFromParent)
print( get_selection(display, window, "CLIPBOARD", "UTF8_STRING") or \
get_selection(display, window, "CLIPBOARD", "STRING") )
I favor a Tkinter-based solution over one which requires pygtk, simply because of the potential the latter has for installation challenges. Given this, my recommendation to Alvin Smith is to read: Cut & Paste Text Between Tkinter Widgets
You can use this code in a Tkinter event handler (from python-list via Tkinter Clipboard access):
data = event.widget.selection_get(selection="CLIPBOARD"))
You can do this with pygtk. A clean solution but might be a bit overkill depending on your application.
Another method that gets some google-hits is to make a system call to xsel.
you might find this thread useful: How does X11 clipboard handle multiple data formats?
Using the clipboard module
First, install the clipboard module using pip3:
$ sudo pip3 install clipboard
Using this cross-platform module (Linux, Mac, Windows) is pretty straightforward:
import clipboard
clipboard.copy('text') # Copy to the clipboard.
text = clipboard.paste() # Copy from the clipboard.
Is it possible for python to accept input like this:
Folder name: Download
But instead of the user typing "Download" it is already there as a initial value. If the user wants to edit it as "Downloads" all he has to do is add a 's' and press enter.
Using normal input command:
folder=input('Folder name: ')
all I can get is a blank prompt:
Folder name:
Is there a simple way to do this that I'm missing?
The standard library functions input() and raw_input() don't have this functionality. If you're using Linux you can use the readline module to define an input function that uses a prefill value and advanced line editing:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt) # or raw_input in Python 2
finally:
readline.set_startup_hook()
I'm assuming you mean from the command-line. I've never seen initial values for command line prompts, they're usually of the form:
Folder [default] :
which in code is simply:
res = raw_input('Folder [default] : ')
res = res or 'default'
Alternatively, you can try to do something using the curses module in Python.
This works in windows.
import win32console
_stdin = win32console.GetStdHandle(win32console.STD_INPUT_HANDLE)
def input_def(prompt, default=''):
keys = []
for c in unicode(default):
evt = win32console.PyINPUT_RECORDType(win32console.KEY_EVENT)
evt.Char = c
evt.RepeatCount = 1
evt.KeyDown = True
keys.append(evt)
_stdin.WriteConsoleInput(keys)
return raw_input(prompt)
if __name__ == '__main__':
name = input_def('Folder name: ')
print
print name
I finally found a simple alternative that works on Windows and Linux. Essentially, i'm using the pyautogui module to simulate the user's input. in practice, it looks like this:
from pyautogui import typewrite
print("enter folder name: ")
typewrite("Default Value")
folder = input()
A Word of Warning:
Theoretically, the user can insert characters in the middle of the "default" input by pressing a key before typewrite finishes.
pyautogui is notoriously unreliable on headless systems, so make sure to provide a backup solution in case the import fails. If you run into No module named 'Xlib', try to install the python3-xlib or python-xlib package (or the xlib module). Running over ssh can also be a problem.
An example fallback implementation:
Since a missing X-server can logically only happen on linux, here's an implementation that uses sth's answer as fallback:
try:
from pyautogui import typewrite
autogui = True
except (ImportError, KeyError):
import readline
autogui = False
def rlinput(prompt, prefill=''):
if autogui:
print(prompt)
typewrite(prefill)
return input()
else:
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt)
finally:
readline.set_startup_hook()
I think that the best (the easiest and most portable) solution is a combination of #rlotun and #Stephen answers:
default = '/default/path/'
dir = raw_input('Folder [%s]' % default)
dir = dir or default
I would like to suggest using the clipboard to solve this problem. Paste the clipboard into the input line, edit as required, press enter. Variable clpstack is used to protect existing clipboard contents. This code is for Windows. Linux could use import clipboard.
import pyperclip as clp
clpstack=clp.paste()
clp.copy("192.168.4.1")
HOST = input("Enter telnet host: ")
clp.copy(clpstack)
I found PyInquirer to be very helpful, especially when building interactive console applications frequently. Prompting a user with a default modifiable value would look as follows:
from PyInquirer import prompt
question = [
{
'type': 'input',
'name': 'first_name',
'message': 'Name please',
'default': 'Max'
}
]
answer = prompt(question)
print('Hello {}'.format(answer['first_name']))
Recently faced this problem. None of the above answers seem to be flawless. So I did some research, and found the following solution to be the easiest, and works both for Windows and Linux:
import keyboard
def input_with_default(prompt_, default_):
keyboard.write(default_)
return input(prompt_)
if __name__ == "__main__":
print(input_with_default("Please enter: ", "hello world"))
I like this, It works on window
def inputWdefault(prompt, default):
bck = chr(8) * len(default)
ret = input(prompt + default + bck)
return ret or default
I liked the approach taken by #MCO so I refactored the code. I tested it on X Windows and Microsoft Windows 10 WSL 2 using Microsoft Terminal:
def input_with_default(prompt, prefill=''):
try:
from pyautogui import typewrite
print(prompt)
typewrite(prefill)
return input()
except (ImportError, KeyError):
import readline
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt)
finally:
readline.set_startup_hook()
Not the best aproach but for the sake of sharing...
You could use Javascript to get all sort of inputs in IPython Notebook.
from IPython.display import HTML
newvar = ""
htm = """
<input id="inptval" style="width:60%;" type="text" value="This is an editable default value.">
<button onclick="set_value()" style="width:20%;">OK</button>
<script type="text/Javascript">
function set_value(){
var input_value = document.getElementById('inptval').value;
var command = "newvar = '" + input_value + "'";
var kernel = IPython.notebook.kernel;
kernel.execute(command);
}
</script>
"""
HTML(htm)
On the next cell you can use the new variable:
print newvar
We can use Tkinter and use a StringVar to do this. The limitation is that the input is through a Tkinter window.
from tkinter import Tk, LEFT, BOTH, StringVar
from tkinter.ttk import Entry, Frame
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Entry")
self.pack(fill=BOTH, expand=1)
self.contents = StringVar()
# give the StringVar a default value
self.contents.set('test')
self.entry = Entry(self)
self.entry.pack(side=LEFT, padx=15)
self.entry["textvariable"] = self.contents
self.entry.bind('<Key-Return>', self.on_changed)
def on_changed(self, event):
print('contents: {}'.format(self.contents.get()))
return True
def main():
root = Tk()
ex = Example(root)
root.geometry("250x100+300+300")
root.mainloop()
if __name__ == '__main__':
main()
If you are writing a CLI, you might want to consider using the python-click library for this.
You would achieve your goal with the following code:
import click
user_input = click.prompt(text="Folder name", default="Download")
print(f"{user_input=}")
If you run this code, and type in nothing, then you get:
$ python3 cli_code.py
Folder name [Download]:
user_input='Download'
If you run this code, and type in 'my-dir', then you get:
$ python3 cli_code.py
Folder name [Download]: my-dir
user_input='my-dir'
Try using an "f-string" and "or" combination, say:
default_name = "that_folder"
this_folder = input(f"Folder name: ({default_name}) ") or default_name
print(this_folder)
If you hit Return without typing in the folder name, the default_name will be assumed.
This is not a very Good Answer but it is a work around for windows. As hard as I tried, I could not get Readline or pyReadline to work on my Windows10 computer with Python Ver 3.5. So I wrote this instead. Not the best code in the world since I've only been using Python for 3 months. But it works.
import os
def note_input(defaultvalue):
#Create a textfile
txtfile = open("txtfile.txt", "w")
#
# populate it with the default value
txtfile.write(defaultvalue)
txtfile.close()
#
# call Notepad
os.system("notepad.exe txtfile.txt")
# input("Just holding until notepad is close : ") (did not need this line)
#
# get the Value Entered/Changed in Notepad
txtfile = open("txtfile.txt", "r")
func_value = txtfile.read()
txtfile.close()
return func_value
# END DEF
Notepad stopped the program from running until it was closed, so the input() line below it was not needed. Once notepad was opened the first time and placed where I wanted it on the screen, It was like a popup input window. I assume you can use any text editor like Notepad++ or Scripe or Code Writer, etc.
If you do that, the user would have to delete the existing word. What about providing a default value if the user hits "return"?
>>> default_folder = "My Documents"
>>> try: folder = input("folder name [%s]:" %default_folder)
... except SyntaxError: folder = default_folder