Print a string, as if user entered it? [duplicate] - python

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

Related

Display full help text in python click

I am having the following problem and I am fearful there isn't a straghtforward way to solve it so I am asking here. I am using Click to implement a CLI and I have created several grouped commands under the main command. This is the code:
#click.group()
def main():
pass
#main.command()
def getq():
'''Parameters: --questionnaire_id, --question_id, --session_id, --option_id'''
click.echo('Question Answers')
When I type the main command alone in my terminal it lists all the subcommands with the help text next to each one. However, the text is not displayed fully for the case of getq. Instead, it displays only "Parameters: --questionnaire_id, --question_id,... ."
Is there a way to display it all?
Thank You
The easiest way to do this is to use the command's short_help argument:
#click.group()
def main():
pass
#main.command(short_help='Parameters: --questionnaire_id, --question_id, --session_id, --option_id')
def getq():
click.echo('Question Answers')
If you insist to use the docstring for this and want to override the automatic shortening of it, then you could use a custom Group class overriding the format_commands method to directly use cmd.help instead of the get_short_help_str method:
import click
from gettext import gettext as _
class FullHelpGroup(click.Group):
def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
"""Extra format methods for multi methods that adds all the commands
after the options.
"""
commands = []
for subcommand in self.list_commands(ctx):
cmd = self.get_command(ctx, subcommand)
# What is this, the tool lied about a command. Ignore it
if cmd is None:
continue
if cmd.hidden:
continue
commands.append((subcommand, cmd))
# allow for 3 times the default spacing
if len(commands):
limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands)
rows = []
for subcommand, cmd in commands:
help = cmd.help if cmd.help is not None else ""
rows.append((subcommand, help))
if rows:
with formatter.section(_("Commands")):
formatter.write_dl(rows)
#click.group(cls=FullHelpGroup)
def main():
pass
#main.command()
def getq():
'''Parameters: --questionnaire_id, --question_id, --session_id, --option_id'''
click.echo('Question Answers')
if __name__ == "__main__":
main()
You most probably want to override the max_content_width (at most 80 columns by default) also. You could do this by overriding the context settings:
import shutil
#click.group(cls=FullHelpGroup,
context_settings={'max_content_width': shutil.get_terminal_size().columns - 10})
def main():
pass

I'm new to coding & I'm learning python and I wrote some code but there's a function that never works and the reason isn't that obvious for me

If I call this function, it never works, just like it never gets called and without errors, even tho (parameter == 'h') is True, and the help function works, and the function is called properly.
I tried everything I could think of.
Function:
def nav(parameter):
if parameter == 'h':
help(parameter)
Help Function:
def help(parameter):
clearConsole()
print("Help Menu")
# other code
How I called it:
nav(userInput)
I think this is what you are trying to accomplish :
def nav(parameter):
if parameter == 'h':
help(parameter)
def help(parameter):
clearConsole()
print("Help Menu")
# other code
import os
def clearConsole():
command = 'clear'
if os.name in ('nt', 'dos'): # If Machine is running on Windows, use cls
command = 'cls'
os.system(command)
user_input = input("Enter a character : ")
nav(user_input)
things I added :
user input
clearConsole() method

How to set the default open path for a Gtk.FileChooserWidget?

If I set the current folder via the method Gtk.FileChooserWidget.set_current_folder(), the first time I open the file chooser, it opens on the location used as argument for set_current_folder()
But, if I select a file, the I re-open the file-chooser, it opens on the "most_recent_used_files".
I'd like it opens on the last selected file's folder path.
How to do it?
Thank you.
From the docs:
Old versions of the file chooser's documentation suggested using gtk_file_chooser_set_current_folder() in various situations, with the intention of letting the application suggest a reasonable default folder. This is no longer considered to be a good policy, as now the file chooser is able to make good suggestions on its own. In general, you should only cause the file chooser to show a specific folder when it is appropriate to use gtk_file_chooser_set_filename() - i.e. when you are doing a File/Save As command and you already have a file saved somewhere.
You may or may not like the reasoning for this behavior. If you're curious about how it came about, see File chooser recent-files in the mailing list and Help the user choose a place to put a new file on the GNOME wiki.
Setting the current folder each time works for me, but it is a little tricky. I'm using Gtk 3.14 and Python 2.7.
You have to get the filename before resetting the directory, or it's lost, and the current directory may be None, so you have to check for that.
This code is tested on Debian jessie and Windows 7.
import os.path as osp
from gi.repository import Gtk
class FileDialog(Gtk.FileChooserDialog):
def __init__(self, parent, title):
Gtk.FileChooserDialog.__init__(self, title, parent)
self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
self.add_button(Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
self.set_current_folder(osp.abspath('.'))
def __call__(self):
resp = self.run()
self.hide()
fname = self.get_filename()
d = self.get_current_folder()
if d:
self.set_current_folder(d)
if resp == Gtk.ResponseType.OK:
return fname
else:
return None
class TheApp(Gtk.Window):
def on_clicked(self, w, dlg):
fname = dlg()
print fname if fname else 'canceled'
def __init__(self):
Gtk.Window.__init__(self)
self.connect('delete_event', Gtk.main_quit)
self.set_resizable(False)
dlg = FileDialog(self, 'Your File Dialog, Sir.')
btn = Gtk.Button.new_with_label('click here')
btn.connect('clicked', self.on_clicked, dlg)
self.add(btn)
btn.show()
if __name__ == '__main__':
app = TheApp()
app.show()
Gtk.main()

Icon overlay in windows not reflecting in explorer

I m using python2.7 and py2exe to create dll from my python script.
Successfully created a DLL and registered an entry for my icon overlay status and then restarted windows explorer process through task manager.
Verified whether my entry is in registry and Yes, it was there.
But when i set my status through a python test app script for a specific folder location.
I expected all the files and folders in the selected path should overlayed with my overlay icon.
But No, Icon overlay is not happening at all.
But when i m testing through python script for register entry(without creating DLL) and setting my icon overlay through my test app script.
Yes, Its working perfectly.
I am confused why it is not happening when tried with my DLL???
Below is my python script to register an status entry
import os
import win32traceutil
import pythoncom
import winerror
from win32com.shell import shell, shellcon
from multiprocessing.connection import Client
REG_PATH = r'Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers'
REG_KEY = "IconOverlayTest"
class IconOverlay:
_reg_desc_ = 'Icon Overlay COM Server'
_public_methods_ = ['GetOverlayInfo', 'GetPriority','IsMemberOf']
_com_interfaces_ = [shell.IID_IShellIconOverlayIdentifier, pythoncom.IID_IDispatch]
def __init__(self, *_args, **_kwargs):
self._icon = None
self._icon_id = None
raise NotImplementedError
def GetOverlayInfo(self):
return self._icon, 0, shellcon.ISIOI_ICONFILE
def GetPriority(self):
return 0
def IsMemberOf(self, path, _attrs):
if is_member(path, self._icon_id):
return winerror.S_OK
return winerror.E_FAIL
class IconOverlay_test(IconOverlay):
_reg_progid_ = 'a.TestServer1'
_reg_clsid_ = '{8B19F050-8354-11E1-A0FE-5C260A5D15E4}'
def __init__(self):
self._icon = "C:\\Users\\Administrator\\mat\\icon_overlay\\icons\\1.ico"
self._icon_id = 101
classes = [IconOverlay_test,]
def is_member(path, icon_id):
try:
conn = None
conn = Client("\\\\.\\pipe\\test.listener", "AF_PIPE")
conn.send(path)
if conn.poll(3):
reply = conn.recv()
return reply == icon_id
except Exception:
pass
finally:
conn and conn.close()
return False
def DllRegisterServer():
print("Registering %s ......."%IconOverlay._reg_desc_)
import winreg
#winreg = _winreg
for view in [winreg.KEY_WOW64_64KEY, winreg.KEY_WOW64_32KEY]:
for cls in classes:
with winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, r"%s\%s" %
(REG_PATH, cls._reg_progid_), 0,
winreg.KEY_ALL_ACCESS|view) as hkey:
print(" %s"%cls)
winreg.SetValueEx(hkey, None, 0, winreg.REG_SZ, cls._reg_clsid_)
print("Registration complete: %s" % IconOverlay._reg_desc_)
def DllUnregisterServer():
print("Unregistering %s ......."%IconOverlay._reg_desc_)
import winreg
#winreg = _winreg
for view in [winreg.KEY_WOW64_64KEY, winreg.KEY_WOW64_32KEY]:
for cls in classes:
try:
_key = winreg.DeleteKeyEx(winreg.HKEY_LOCAL_MACHINE, r"%s\%s"
% (REG_PATH, cls._reg_progid_),
winreg.KEY_ALL_ACCESS|view)
except WindowsError as err:
if err.errno != 2:
raise
print("Unregistration complete: %s" % IconOverlay._reg_desc_)
if __name__ == '__main__':
from win32com.server import register
register.UseCommandLine(*classes,
finalize_register = DllRegisterServer,
finalize_unregister = DllUnregisterServer)
This is really painful to get working right, goodluck!
I believe windows will only allow 10 different icons to be registered and it will only work with the first 10 registered alphabetically. Do you already have 10 registered? It's quite easy to exceed 10 if you have dropbox, tortoise-svn etc. installed as each image counts as an entry. If that's the case try putting an underscore or a 0 before the name to make sure it gets priority, although it will mean another icon will lose out- I don't think there's a way around this.
Also sometimes windows doesn't know to refresh the status of the icon. Which version of windows are you running? Some are worse than others. I seem to remember XP isn't very good at this. There's some tricks to get it to update though, you can refresh the window through windows api, but it looks horrible and the whole of explorer flashes. A better way I found is to change the an attribute on the file. This is the trick I used:
import stat,os
file_att= os.stat(path)[0]
if file_att & stat.S_IWRITE:
os.chmod(path,stat.S_IREAD)
os.chmod(path,stat.S_IWRITE)
else:
os.chmod(path,stat.S_IWRITE)
os.chmod(path,stat.S_IREAD)

How to monitor Python files for changes?

I want to restart my Python web application, if code gets changed. But there could be a large number of files that could be changed, since files in imported modules could change ...
How to get the actual file names from imported packages / modules?
How can modified Python files be detected efficiently? Is there a library to do that?
Shameless plug. There's also http://github.com/gorakhargosh/watchdog that I'm working on to do exactly this.
HTH.
gamin is another option which is slightly less Linux-specific.
I'm not sure how you would implement the 'reload application' operation in your circumstance; reloading a changed module with the reload built-in probably won't cut it.
But as far as detecting whether or not there was a change, the following would be one way to approach it.
Most python modules have a __file__ attribute.
All loaded modules are stored in sys.modules.
We can walk through sys.modules at some interval, and look for changes on disk for each module in turn
Sometimes __file__ points to a .pyc file instead of a .py file, so you might have to chop off the trailing c. Sometimes a .pyc file exists but a .py doesn't exist; in a robust system you'd have to allow for this.
A proof of concept of code to do this (not robust):
_module_timestamps = {}
_checking = False
def run_checker():
global _checking
_checking = True
while _checking:
for name, module in sys.modules.iteritems():
if hasattr(module, '__file__'):
filename = module.__file__
if filename.endswith('.pyc'):
filename = filename[:-1]
mtime = os.stat(filename).st_mtime
if name not in _module_timestamps:
_module_timestamps[name] = mtime
else:
if mtime > _module_timestamps[name]:
do_reload(name)
else:
'module %r has no file attribute' % (name,)
time.sleep(1)
def do_reload(modname):
print 'I would reload now, because of %r' % (modname,)
check_thread = threading.Thread(target=run_checker)
check_thread.daemon = True
check_thread.start()
try:
while 1:
time.sleep(0.1)
except KeyboardInterrupt:
print '\nexiting...'
Here's an example of how this could be implemented using pyinotify (ie., on Linux).
from importlib import import_module
class RestartingLauncher:
def __init__(self, module_name, start_function, stop_function, path="."):
self._module_name = module_name
self._filename = '%s.py' % module_name
self._start_function = start_function
self._stop_function = stop_function
self._path = path
self._setup()
def _setup(self):
import pyinotify
self._wm = pyinotify.WatchManager()
self._notifier = pyinotify.ThreadedNotifier(
self._wm, self._on_file_modified)
self._notifier.start()
# We monitor the directory (instead of just the file) because
# otherwise inotify gets confused by editors such a Vim.
flags = pyinotify.EventsCodes.OP_FLAGS['IN_MODIFY']
wdd = self._wm.add_watch(self._path, flags)
def _on_file_modified(self, event):
if event.name == self._filename:
print "File modification detected. Restarting application..."
self._reload_request = True
getattr(self._module, self._stop_function)()
def run(self):
self._module = import_module(self._module_name)
self._reload_request = True
while self._reload_request:
self._reload_request = False
reload(self._module)
getattr(self._module, self._start_function)()
print 'Bye!'
self._notifier.stop()
def launch_app(module_name, start_func, stop_func):
try:
import pyinotify
except ImportError:
print 'Pyinotify not found. Launching app anyway...'
m = import_module(self._module_name)
getattr(m, start_func)()
else:
RestartingLauncher(module_name, start_func, stop_func).run()
if __name__ == '__main__':
launch_app('example', 'main', 'force_exit')
The parameters in the launch_app call are the filename (without the ".py"), the function to start execution and a function that somehow stops the execution.
Here's a stupid example of an "app" that could be (re-)launched using the previous code:
run = True
def main():
print 'in...'
while run: pass
print 'out'
def force_exit():
global run
run = False
In a typical application where you'd want to use this, you'd probably have a main loop of some sort. Here's a more real example, for a GLib/GTK+ based application:
from gi.repository import GLib
GLib.threads_init()
loop = GLib.MainLoop()
def main():
print "running..."
loop.run()
def force_exit():
print "stopping..."
loop.quit()
The same concept works for most other loops (Clutter, Qt, etc).
Monitoring several code files (ie. all files that are part of the application) and error resilience (eg. printing exceptions and waiting in an idle loop until the code is fixed, then launching it again) are left as exercises for the reader :).
Note: All code in this answer is released under the ISC License (in addition to Creative Commons).
This is operating system specific. For Linux, there is inotify, see e.g. http://github.com/rvoicilas/inotify-tools/

Categories