Running an existing tkinter script from another tkinter script - user-interface

I'm new to python and tkinter.
I have a working tkinter script (Which I would like to avoid editing)
Now I'm writing a script which will be top level GUI.
The button from this script should launch my existing script with some command line arguments (like running it from a shell i.e. python3.4.1 script.py args).
I have tried the following:
Using os.system
btn2 = Button(frame2, text="Configure>>", command="os.system('python script.py args')")
Using subprocess
def runSubProcess(self):
p=subprocess.Popen(["python3.4.1","script.py args"],stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output=p.communicate()[0]
Both methods are not working.
Any suggestions are welcome and thanks.
Edit: Also I don't need to communicate with the new window, as it'll be writing to a file which will be used later. Just the control return from child to parent window should suffice (upon clicking OK)
-Vinay

Your first method should work. However, you passed the wrong thing to the command argument for the Button. You should pass a function to the command instead of a string. You can use lambda:
btn2 = Button(frame2, text="Configure>>", command=lambda: os.system('python script.py args'))

Related

Passing arguments to macos app when bundle executable is a Bash script

I've created an .app (a macOS bundle) where the main executable is a Bash script, following the instructions I found in StackOverflow and other places. It works perfectly except for the fact that when I double click on a file associated with the .app, the script is run but it doesn't get the clicked file name as an argument.
Looks like the problem is that the script doesn't handle the "OpenFile" event, but I don't know if there's a way where the user double-clicks a file and the file name is passed to the .app bundle executable as a command line parameter and not through some event.
#! /usr/local/bin/bash
source ~/.bashrc
python3 final_script.py $1
# Above, "$1" is empty. I've tried some variations,
# including not running the second script, to no avail.
I know I can use py2app to achieve something similar, or Platypus, or Automator, etc. but using a Bash script is better for my workflow and also I'm curious about how macos passes parameters to apps when a file is double-clicked.
Thanks a lot in advance!
Finally I found the way. Simpler than I thought, and it was not easy to find but...
The Bash launcher won't get anything in the command line because that's NOT the way macOS handles arguments in app bundles, it uses Apple Events. I didn't know this, and it's my fault, my lack of expertise in macOS.
Turns out tkinter actually supports Apple Events, at least the odoc one, which is the one the app bundle gets when the user double clicks a document to be opened by an app.
So, what I did was modifying final_script.py, adding the following code:
import sys
import tkinter
def handle_opendocument(widget, *args):
message = ''
for arg in args:
message += str(arg) + '\n'
widget.configure(text=message.rstrip())
...
# More code here...
...
root = tkinter.Tk()
root.title('Testing AppleEvent handling in Python/Tk')
root.createcommand('tk::mac::OpenDocument', lambda *args: handle_opendocument(label, *args))
label = tkinter.Label(root)
label.configure(text='Starting up...')
label.pack()
root.mainloop()
Of course, the real handle_opendocument function in my app does more things, but I wanted to show the bare minimum necessary to make this work. I hope is helpful!

Python subprocess.Popen terminates when stdin=PIPE is specified

I'm new to subprocesses in python, I need to spawn a number of independent subprocesses, keep them alive and pass commands into them. At first sight, subprocess library is what I'm looking for.
I've read the documenations for it and as I'm understanding to pass any command into the subprocess, I'd have to specify the input.
I need to run commands via windows command line, hence the toy example below is good enough that if I have it working, I'm pretty much done. Running code below via IDLE opens a new cmd window, printing a list of cwd files, however I can't write to it as stdin is not specified (would be writing to it using p.stdin.write('DIR') with 'DIR' being an example command).
from subprocess import Popen, PIPE
p = Popen(['cmd', '/K', 'DIR'])
Therefore I specify the stdin as PIPE, as per documentations.
from subprocess import Popen, PIPE
p = Popen(['cmd', '/K', 'DIR'], stdin=PIPE)
However, running the second snippet of code instantly terminates the opened cmd window. Is that the expected behavior? As far as I could find in the documentations, only p.kill() or p.terminate() end the child process. If so, what are the possible workarounds? If not, what am I doing incorrectly, what other libraries should I be using? Thanks!

Checking for a running python process using python

I have a python script called speech.pyw. I don't want it showing up on the screen when run so I used that extension.
How can I check using another python script whether or not this script is running? If it isn't running, this script should launch it.
Off the top of my head, there are at least two ways to do this:
You could make the script create an empty file in a specific location, and the other script could check for that. Note that you might have to manually remove the file if the script exits uncleanly.
You could list all running processes, and check if the first one is among those processes. This is somewhat more brittle and platform-dependant.
An alternative hybrid strategy would be for the script to create the specific file and write it's PID (process id) to it. The runner script could read that file, and if the specified PID either wasn't running or was not the script, it could delete the file. This is also somewhat platform-dependant.
!/usr/bin/env python2
import psutil
import sys
processName="wastetime.py"
def check_if_script_is_running(script_name):
script_name_lower = script_name.lower()
for proc in psutil.process_iter():
try:
for element in proc.cmdline():
if element.lower() == script_name_lower:
return True
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return False;
print(check_if_script_is_running(processName))
sys.stdin.readline()

python Input delegation for subprocesses

I am currently displaying the output of a subprocess onthe python shell (in my case iDLE on windows) by using a pipe and displaying each line.
I want to do this with a subprocess that has user input, so that the prompt will appear on the python console, and the user can enter the result, and the result can be send to the subprocess.
Is there a way to do this?
Use process.stdin.write.
Remember to set stdin = subprocess.PIPE when you call subprocess.Popen.

Remotely manipulating the execution of a batch file

I have a batch file that is located on one machine that I am invoking remotely from another machine. That batch file is pretty simple; all it does is set some environment variables and then executes an application - the application creates a command window and executes inside of it. The application it executes will run forever unless someone types in the command window in which it is executing "quit", at which point it will do some final processing and will exit cleanly. If I just close the command window, the exit is not clean and that is bad for a number of different reasons related to the data that this application produces. Is there a way for me to perhaps write another batch script that will insert the "quit" command into the first command window and then exit?
I'd write a little script using the subprocess module in python, like so:
from subprocess import Popen, PIPE
import os
import os.path
import time
app = Popen(['c:/path/to/app.exe', 'arg1', 'arg2'], stdin=PIPE, env = {
'YOUR_ENV_VAR_1': 'value1',
'YOUR_ENV_VAR_2': 'value2',
# etc as needed to fill environment
})
while not os.path.exists('c:/temp/quit-app.tmp'):
time.sleep(60)
app.communicate('quit\n')
print "app return code is %s" % app.returncode
Then, you remotely invoke a batch script that creates c:/temp/quit-app.tmp when you want to shut down, wait a couple of minutes, and then deletes the file.
Naturally, you need Python installed on the Windows machine for this to work.
It sounds like the type of job for which I'd use expect, though I've never used it under Windows.
You could use the < to take the "quit" from a text file instead of the console... but that would quit your process as soon as it loads. Would that work?
Otherwise you could write a program to send keystrokes to the console... but I don't think this is a production quality trick.
Do you have access to the actual code of the application? if so you can check for a batch file. Else you can do something like the following using powershell.
$Process = Get-Process | Where-Object {$_.ProcessName -eq "notepad"}If (!($Process))
{ "Process isn't running, do stuff"
}Else
{ $myshell.AppActivate("notepad")
$myshell.sendkeys("Exit")
}
I am only suggesting powershell as its easy for you to call the code. you could also put in a loop and wait for it to run.
RE

Resources