Win32API commands seem not to work with PowerShell (I'm running 7, but I assume unimportant), only with the inferior IMHO Command Prompt.
I am building a program (a glorified HOSTS site blocker) that runs on the simple structure of "query command, execute command; repeat until user prompts to exit" and one of the things the user can query the program with is UNBLOCK category>site_nickname FOR minutes. This runs the program in one thread, starts a timer in another thread so the user can keep using the program as they desire. After the timer, the UNBLOCK command the program ran at start is undone so the user can get back to work. What I want to avoid is the user being able to cheat fate by saying UNBLOCK, then closing the program via the 'close' button, terminating the PowerShell instance, my Python program, and all its threads and thus ensuring the UNBLOCK command is never undone with a partner BLOCK command.
The user can exit the program by typing EXIT or CANCEL. This has the program wrap up, and then run sys.exit(). As I discovered, using the atexit library just basically does that but runs the function you want afterwards, does not intercept a close-button click. And setting the console control handler only seems to work in Command Prompt (whose support for ANSI escapes/emojis/Unicode probably too, seems to be spotty), also, the window_exit() function, or I guess the proper term is "method" --
def window_exit(signal_type):
sure = ask_input("Wait, wait! Are you sure you want to exit?") # input plus ANSI escape sequence, highlights the input prompt in blue and adds ">>" on a new line
if sure == "Yes":
evaluate("EXIT") # runs this command as if the user typed it in to be evaluated by my program
-- does not accept input properly. Instead, it displays the message and then for some reason decides I am trying to pull some "Press any key to continue ..."-type stuff, when I want the user to be able to type whatever and then have it be evaluated.
What can I do so any attempt to "cheat" and exit the program early is acknowledged and dealt with?
Related
I am trying to use python to take in a string from a barcode scanner and use it to select a laser engraver file to execute. I am able to get the Max Marking (laser software) to open with the correct file, but am getting lost after that. I want to press "f2", which is the hotkey to run the laser, then wait on the "etching" prompt that the Max Marking software displays on the screen, then close Max Marking. I suppose I could test each of the engravings for their respective lengths of time and just use time.sleep(SomeAmountOfTime), but would like to make closing the program literally contingent on the engraving finishing. Is there a way to make python wait on the "currently etching" prompt that displays while the laser is running? This is within the Max Marking application and not a windows prompt. Here is what I have so far...
def notepad():
os.startfile('....filepath....')
time.sleep(2)
pyautogui.press('f2')
#Where I need to wait on etching prompt
os.system('taskkill /f /im maxmarking.exe')
A very simple solution could be _ = input("press ENTER when etching is finished"), it is not automatic but reliable.
If you want something completely automatic, it will be much more difficult. To detect that the prompt in another process has been displayed, either it provides an API to do that (which I doubt) or it will be very hacky (see the whole topic of "window automation", for exemple this question).
If having to return to the Python executing script is bothersome, you could use a hotkey to message it, see for example this question.
I'm currently making a lil' launcher for PortableMu while in an internship.
We (company and I) modeled a special mode for the Mu-Editor and we are shipping it with PortableMu so that users don't need to install Mu and/or Python to use it.
The problem of PortableMu for Windows is, that you start it with a .bat and this doesnt give you any feedback.
You click, you wait ~1-2min and maybe Mu-Editor will popup.
This is not very userfriendly.
So my duty is to create a launcher.
My launcher is a simple thing: Only lil "welcome" a picture and a button to start PortableMu. It works on my private windows10.
Now I want to add in randomly picked messages for simulating "loading" which shall stop when the Mu-Editor pops up. Simply to bridge the time
Is there a method to catch when this happens?
Alas:
Can Python catch the moment when Windows opens the task/process for Mu-Editor?
If, how?
use the tasklist
subprocess.Popen('tasklist').comunicate()[0] will return all the tasks currently happening in windows, simply do this every minute or so and check for your task. There are ways to make this pass without a command window popping up, here's one that i use often
command =subprocess.Popen(["ping","-n","1","-w","100", str(ip)], stdout=subprocess.PIPE, shell=False, creationflags = 0x08000000)
reply = str(command.communicate()[0])
i write some python program.
i usually execute my program by CMD
but this time, i tried to execute program by double click
it works well until interpreter meet input code.
when i input some texts, it shut down
my input code is
for i in (input('range input => ')).split(' '):
range_list.append(int(i));
it works totally well when i execute by path(py ~.py) through the CMD
can you help me?
The interpreter is running in an endless loop. Executing your program from windows or via the command line using python will run and exit the program immediately.
At the end of your program just add
input()
This will keep it open so you can see your results.
Yeah when the program is done, it closes.
You can add something like x = input() at the end if you want to keep it open, or just run it in cmd.
Your program opens in a windowed mode when you double click it. The window will disappear / close down when the program finishes, which happens a lot fast after you have entered all the required inputs.
If you wish to see the output before the program exit, expect an input at the end of your program.
Note: This is somewhat a follow-up on the question: Tkinter - when do I need to call mainloop?
Usually when using Tkinter, you call Tk.mainloop to run the event loop and ensure that events are properly processed and windows remain interactive without blocking.
When using Tkinter from within an interactive shell, running the main loop does not seem necessary. Take this example:
>>> import tkinter
>>> t = tkinter.Tk()
A window will appear, and it will not block: You can interact with it, drag it around, and close it.
So, something in the interactive shell does seem to recognize that a window was created and runs the event loop in the background.
Now for the interesting thing. Take the example from above again, but then in the next prompt (without closing the window), enter anything—without actually executing it (i.e. don’t press enter). For example:
>>> t = tkinter.Tk()
>>> print('Not pressing enter now.') # not executing this
If you now try to interact with the Tk window, you will see that it completely blocks. So the event loop which we thought would be running in the background stopped while we were entering a command to the interactive shell. If we send the entered command, you will see that the event loop continues and whatever we did during the blocking will continue to process.
So the big question is: What is this magic that happens in the interactive shell? What runs the main loop when we are not doing it explicitly? And why does it need to halt when we enter commands (instead of halting when we execute them)?
Note: The above works like this in the command line interpreter, not IDLE. As for IDLE, I assume that the GUI won’t actually tell the underlying interpreter that something has been entered but just keep the input locally around until it’s being executed.
It's actually not being an interactive interpreter that matters here, but waiting for input on a TTY. You can get the same behavior from a script like this:
import tkinter
t = tkinter.Tk()
input()
(On Windows, you may have to run the script in pythonw.exe instead of python.exe, but otherwise, you don't have to do anything special.)
So, how does it work? Ultimately, the trick comes down to PyOS_InputHook—the same way the readline module works.
If stdin is a TTY, then, each time it tries to fetch a line with input(), various bits of the code module, the built-in REPL, etc., Python calls any installed PyOS_InputHook instead of just reading from stdin.
It's probably easier to understand what readline does: it tries to select on stdin or similar, looping for each new character of input, or every 0.1 seconds, or every signal.
What Tkinter does is similar. It's more complicated because it has to deal with Windows, but on *nix it's doing something pretty similar to readline. Except that it's calling Tcl_DoOneEvent each time through the loop.
And that's the key. Calling Tcl_DoOneEvent repeatedly is exactly the same thing that mainloop does.
(Threads make everything more complicated, of course, but let's assume you haven't created any background threads. In your real code, if you want to create background threads, you'll just have a thread for all the Tkinter stuff that blocks on mainloop anyway, right?)
So, as long as your Python code is spending most of its time blocked on TTY input (as the interactive interpreter usually is), the Tcl interpreter is chugging along and your GUI is responding. If you make the Python interpreter block on something other than TTY input, the Tcl interpreter is not running and the your GUI is not responding.
What if you wanted to do the same thing manually in pure Python code? You'd of need to do that if you want to, e.g., integrate a Tkinter GUI and a select-based network client into a single-threaded app, right?
That's easy: Drive one loop from the other.
You can select with a timeout of 0.02s (the same timeout the default input hook uses), and call t.dooneevent(Tkinter.DONT_WAIT) each time through the loop.
Or, alternatively, you can let Tk drive by calling mainloop, but use after and friends to make sure you call select often enough.
I have a python program that displays battery voltages and temperatures in an electric car. I typically run it from a command line on a Mac by simply using the up arrow to find the command to change directory, and then up arrow to find the command to run the program. We figured out how to write a script that does this automatically and saved it as an application. It works great but don't know how to exit the program. I use control C when using the command line. How do I accomplish in in a script or app? I prefer not to ask our customers to use the command line.
import sys; sys.exit()
will stop the Python program. When you call that code is up to you and depends on the details of your program (you could have it happen when a certain button is pressed, or after a certain amount of time, or when other conditions are met). Also be careful if you have to do any "clean-up" before the program ends- this also depends on the type of application.
If for some reason you want to stop it in exactly the same way as hitting Control-C, you could do
raise KeyboardInterrupt