Keeping track of current input before user presses enter - python-3.x

I'm using Python's cmd module to handle a terminal input loop.
I have a thread running in the background, which prints out some stuff in the terminal when it receives a message. These messages break the visual user input:
> writing a com
### message generated from a thread and printing during user input ###
mand
I ask a related question here and was basically told that one way to avoid breaking the user's input would be to keep track of user input, so that when a message comes in I can print the message and the reprint the user input. When I asked that question I wasn't using the cmd module.
When using the cmd module, how would I keep track of what the user has currently typed, so that I can reprint it after?

I discovered the readline module and it's get_line_buffer() method.
Here's how I solved it, in the thread that wants to print out data while I'm reading user input in the main:
import readline
# Save the current buffer
current_buffer = readline.get_line_buffer()
# Print our stuff, note the \r is important to overwrite the current buffer
print("\rladida interruption\nsome more interruption\n")
# Reprint our buffer
print('> ' + current_buffer, end='', flush=True)
Here's an example, before:
$ ./main.py
> help
and after:
$ ./main.py
ladida interruption
some more interruption
> help
Note how the command prompt cleanly moved down, with the users current command input in place. The cursor is also in the right position to continue typing, backspace works fine too.

Related

How to run python scipt in the background(after user input) even if the terminal is closed

I have a python script that takes some inputs from the user & then executes the code based on the input. The code takes some time to complete; during this code runtime the user can close the terminal(the code is run from a Linux machine)
As soon as the user closes the terminal the script stops as well. I know there are options like nohup but it wouldn't accept any input(where input is required in my script).
How can I fix this?
Requirement is -
Run the script, enter the inputs
Let the code run in the background even if the terminal is closed
Also is there a way to write whatever is being printed in the terminal(during the script runtime) to some file
Linux's screen tmux served my purpose.
There is a work around possible,
you can split your programm into two parts.
And start your background task with:
import os
usr_inp=input("test input: ")
os.popen(f"python3 background_task.py {usr_inp} &")
This should start the other programm in the background, there you can use the input over the sys.argv[1] variable.
(Usually it's not recommended using os.popen)

How do I avoid losing program focus after subprocess.call?

I am trying to extract data from a program; its raw data files are encrypted XMLs so my plan is to start the program, then use mouse control commands (e.g. pyautogui) to copy / paste the data.
So far I'm falling at the first hurdle; when I run subprocess.call to start the program, the program gets window focus and my subsequent code doesn't execute until I manually close the program.
workingFolder = self.get_working_folder() # get path where raw data is
subprocess.call('Path\Program.exe') # works, Program.exe starts
print(workingFolder) # this doesn't execute until I close the Program window
EDIT: After further testing I have answered my own question - subprocess.Popen was in fact what I needed, despite my initial doubts about it! Thanks to anyone who looked at my question :).
workingFolder = self.get_working_folder()
subprocess.Popen('Path\Program.exe')
print('This works')

Turn off echo of getpass.getpass() in IDLE

I would like to enter a password into the IDLE terminal in Windows without an echo.
Normally entering passwords is possible with python using the function getpass.getpass(), but in IDLE there comes up the following warning message:
GetPassWarning: Can not control echo on the terminal.
Warning: Password input may be echoed.
I found out, this is because IDLE replaces the sys.stdin with a different object:
if sys.stdin is not sys.__stdin__:
return fallback_getpass(prompt, stream)
However, I could not find a solution. Does anybody have an answer or another way to enter a password into the IDLE terminal without an echo?
As an IDLE maintainer with some familiarity with IDLE internals, I do not believe that it is possible to suppress character display but not otherwise change behavior in response to input('prompt') without major changes to IDLE code.
But even that would be insufficient for getpass.getpass since it calls one of unix_getpass, win_getpass, or default_getpass, and the first two use system_specific low-level functions that bypass stdin.
In terms of design intent: IDLE is, as its name says, a program development environment. Developed programs normally, and sometimes must be, executed by Python directly, without going through IDLE. Python normally runs attached to a terminal window. IDLE's Shell is based on a tkinter Text widget, which is a multiline editor, not a terminal. This is why one can enter, recall, and edit complete multiline statements rather than only a single line at a time.

Control - Z In Python Code

In IDLE, there's no clear screen, and after reading the forums the best method is plainly to print a ton of "\n"s. However, after playing with IDLE, I made a discovery. When my game was waiting for an input after printing out instructions using print statements, instead of inputting any useful character, I entered 'control-z,' and IDLE began to remove the text that was display by the print statements, one by one.
My main question is, how do I manually in the code itself enter 'control-z', so I can utilize this functionality?
If you're confused by my story, here's some example code and try it yourself by hitting control-z.
print("Some Text")
print("More Text")
input("The Input (Hit Control - Z Here):")
^Z is a bit of a mess. The ascii control char ^D is usually interpreted as EOT, end of transmission, which on Unix and many other systems means end of file, close the application. Ascii ^Z is meant to be interpreted as SUB, substitute, whatever that means. Editors ofter use it as UNDO (meaning undo a ^X cut). Microsoft (and a few other old systems) at least sometimes interprets ^Z as end of file, with the same effect as ^D on *nix.
The Windows console closes a text app after ^Z . ^D is passes on to the app. IDLE, as a cross-platform app, closes on ^D. IDLE used to close on ^Z on Windows, but now, for me, it only erases the prompt. (I don't know if this alternative is intended.) I do not see the progressive deletion you report. What OS and what Python version are you running?
To answer your main question: you can't. input is usually used in assignment statements: string = input('prompt'). The way to imitate input statements is to directly assign 'user input': s = 'simulated user input'. However, this does not work for characters that get intercepted by the programs managing the input window and never sent to the python program.
IDLE's Shell generally imitates Python's interactive console. The latter (at least on Windows) makes everything, except the current input, read-only. Shell follows suite. Imitation is especially strict as regards executing user code. It is intended that user code tested in IDLE should run in Python without IDLE. It would be wrong for IDLE to clear the interactive shell in response to user code when Python cannot.
For editor and output windows, ^A (select all) followed by Backspace (delete), Delete, or ^X (cut) do clear the window.
Shell does, however, has more editing commands than many (most? all?) consoles and a menu system. These additions are allowed since they are interactive only and not accessible from user code. There have been various proposals and patches to enable clearing part or all of the shell window. https://bugs.python.org/issue6143 has some of the discussions and proposals.

BASH background process printings disappearing the prompt line

I have a BASH script that runs on bg and print messages to the user when according to system events.
My problem is that after the echo of these messages, the user need to press on the ENTER key in order to get back to the prompt line.
Adding new line to the printed messages didn't help since it still comes from the bg and not from the user shell.
Does anyone have an elegant & simple solution to get the user back to the prompt line?
I will appreciate any help here..
You don't need to press enter to get to a prompt. You are still at the prompt that was there before the output was printed. Try just entering a command and hitting enter. (You can also hit ctrl-l to clear the screen instead of hitting enter to input an empty command.)
The problem here is that the background/alternative process has no relationship to the running shell session and so it is simply writing output to wherever the terminal sticks it. The process might be able to use control sequences to control the output location (but I don't know if this actually works).
Other than that there isn't much to be done about this that I'm aware of. And it isn't a problem in any real way.

Resources