I am creating a Python script that asks for input from the command line. The user will have the ability to edit a part of a file. I can ask for the new information and overw
You should just have 2 variables: one for standard string, one for string that will user change by itself. Like:
str1 = 'String that is standard'
str2 = str1 #it usually will be standard string
usr = input('your text goes here')
if len(usr) != 0:
str2 = usr
#and here goes code for writing string into file
I have written a line editor which hopefully does what you are looking for. But it is a quick-and-dirty hack. It is Windows only and written with CPython 3.6.5 on Windows 10, so its use might be limited. It has been tested on codepage 1252 (ANSI Latin 1; Western European (Windows)) and codepage 65001 (utf-8). It is very basic and a bit sluggish as it is not speed-optimized. (I should rewrite it in C but I do not have the time.) It is hardly tested and poorly documented.
import msvcrt
import os
import sys
if os.name != 'nt':
raise NotImplementedError('This module works only on MS Windows!')
CTRL_00 = 0
CTRL_E0 = 224
KEY_BACKSPACE = 8
KEY_DELETE = 83 # CTRL
KEY_END = 79 # CTRL
KEY_ESC = 27
KEY_HOME = 71 # CTRL
KEY_INSERT = 82 # CTRL
KEY_LEFT = 75 # CTRL
KEY_RETURN = 13
KEY_RIGHT = 77 # CTRL
flush = sys.stdout.flush
write = sys.stdout.write
mode = ('[OVR]> ', '[INS]> ') # overwrite, insert
prefix = len(mode[0])
def _update_line(insert, source, length, line, target):
"""Write a new line and position the cursor.
source: previous cursor position
length: old line length
line: edited line
target: next cursor position
"""
write('\b' * source) # set cursor to start of line
write(' ' * length) # erase old line
write('\b' * length) # again, set cursor to start of line
write(mode[insert] + line[prefix:]) # write updated line
write('\b' * (len(line) - target)) # set cursor to new position
flush() # write buffer to screen
def mswin_line_edit(default_string, insert=True):
"""Edit a MS Windows CLI line."""
insert = insert
line = mode[insert] + default_string
count = len(line)
before = line[:count]
after = line[count:]
print(line, end='', flush=True)
cursor = count
while True:
key = msvcrt.getwch()
num = ord(key)
if num == KEY_ESC: # abort edit
return default_string
if num == KEY_RETURN: # finish edit
return line
if num == KEY_BACKSPACE: # delete character before cursor
if cursor > prefix:
before = line[:cursor - 1]
after = line[cursor:]
line = before + after
_update_line(insert, cursor, count, line, cursor - 1)
cursor -= 1
count = len(line)
elif num == CTRL_E0 or num == CTRL_00: # CTRL
ctrl = ord(msvcrt.getwch())
if ctrl == KEY_END: # set cursor after last character
if cursor < count:
before = line
after = ''
_update_line(insert, cursor, count, line, count)
cursor = count
elif ctrl == KEY_HOME: # set cursor before first character
if cursor > prefix:
before = ''
after = line
_update_line(insert, cursor, count, line, prefix)
cursor = prefix
elif ctrl == KEY_LEFT: # move cursor 1 character to the left
if cursor > prefix:
before = line[:cursor]
after = line[cursor:]
_update_line(insert, cursor, count, line, cursor - 1)
cursor -= 1
elif ctrl == KEY_RIGHT: # move cursor 1 character to the right
if cursor < count:
before = line[:cursor]
after = line[cursor:]
_update_line(insert, cursor, count, line, cursor + 1)
cursor += 1
elif ctrl == KEY_DELETE: # delete character after cursor
if cursor < count:
before = line[:cursor]
after = line[cursor + 1:]
line = before + after
_update_line(insert, cursor, count, line, cursor)
count = len(line)
elif ctrl == KEY_INSERT: # switch insert/overwrite mode
insert ^= True
_update_line(insert, cursor, count, line, cursor)
else: # ordinary character
before = line[:cursor] + key
if insert:
after = line[cursor:]
else:
after = line[cursor + 1:]
line = before + after
_update_line(insert, cursor, count, line, cursor + 1)
cursor += 1
count = len(line)
if __name__ == '__main__':
test_string = input('test string: ')
result = mswin_line_edit(test_string)
print(f'\n{result}')
You could do it with tkinter:
from tkinter import *
def enter():
global commandEntry
command = commandEntry.get()
# Do stuff with command
commandEntry.delete(0, END)
def edit_line(line):
global commandEntry
commandEntry.insert(0, line)
root = Tk()
messageVar = StringVar()
messageVar.set("Enter a command:")
message = Label(root, textvariable=messageVar)
commandEntry = Entry(root)
enterButton = Button(root, text="Enter", command=enter)
root.mainloop()
Unfortunately, I don't know if kind of input()
with default value is available in standard library.
There is an external solution - use win32console
as mentioned in this answer. However, it has two pitfalls as far as I can see. First, the import is bundled in a package pywin32. So you would use pip install pywin32
, except it does not work, because of the second pitfall: the information about the package at pypi is outdated, it says that package is incompatible with Python 3.4...
But in fact, it can work! You should follow the "Download URL" visible at pypi project page (i.e. https://sourceforge.net/projects/pywin32/files/pywin32/ ) and install latest build. I just installed build 219 for Py3.4, as I myself also use this Python version. On the page installers are provided for several Python versions for 32bit and 64bit Windows.
Also, I've tweaked the code from above-linked SO answer to work in Python 3:
import win32console
_stdin = win32console.GetStdHandle(win32console.STD_INPUT_HANDLE)
def input_def(prompt, default=''):
keys = []
for c in str(default):
evt = win32console.PyINPUT_RECORDType(win32console.KEY_EVENT)
evt.Char = c
evt.RepeatCount = 1
evt.KeyDown = True
keys.append(evt)
_stdin.WriteConsoleInput(keys)
return input(prompt)
if __name__ == '__main__':
name = input_def('Folder name: ', 'it works!!!')
print()
print(name)
This works on my Windows machine... If this does not work on yours, can you provide the error message?