How to get past a window prompt while calling a subprocess - python

I have a jar file that I want to run in the command line and collect it's stdout with a python script.
I make the call as a subprocess like:
def get_output():
process = subprocess.run(['java', '-jar', 'myjar.jar', 'myfileargument'])
But a warning prompt comes up that I am unable to disable, which pauses execution until a user clicks 'OK' or presses enter. Is there a way to essentially 'click ok' in the prompt window that comes up via code and let the python script continue?

If there is no way for you, only using environment variables and parameters to the subprocess, to disable that warning, there is no easy way to do it.
Either you will have to go the road of UI automation, as mentionned by #furas in the comments. It may be relatively easy to do so given the multiple tools/frameworks there is to do that.
Or you may "patch" the jar to not require this warning. If you can replace the annoying .class file by another which will not require to accept the warning, it may be somewhat efficient. Or else you could install a custom ClassLoader in the java program, but it may prove to be difficult.

Related

Disable subprocess.Popen echo to command prompt window title in Python

I'm trying to use a Python's subprocess.Popen to build up a module for Python bindings to a command line interface; pretty much there as far as the CLI-bindings go, but I really want to be able to mask some "private" arguments.
The CLI uses account information, and I want to hide the account credentials from a command prompt title. Below is a screen capture of what appears when I use the login method for my CLI-bindings class.
I know that I'm using plain text for the password here ('TAIL') but I wanted to simply show the usage of what's going on. See from the image that the full command "sent" using the subprocess.Popen is displayed in the prompt's title.
I recently found that there is a way to programmatically change the title using either os or ctypes, so I could effectively mask, or cover-up, the "private" credentials I don't want shown on the command prompt title like shown here:
but is there a better way of disabling "echo-to-title" (for lack of a better name) with subprocess.Popen?
in fact passwords should never be passed as command line arguments to an executable.
Reason:
anybody being able to look at running processes and their parameters can see the password.
One solution is, that the parent process. puts the password in an environment variable and the program to be called fetches the parameter from an environment variable.
so the caller would be something like:
import os
os.environ["ACRTAC_PASSWORD"] = "TAIL"
subprocess.Popen([...])
and the acrtac.py
import os
password = os.environ["ACRTAC_PASSWORD"]

Write and save a file with nano using subprocess

how can I write/append to a file by calling nano using subprocess and get it saved automatically .For example I have a file and I want to open it and append something at the end of it so I write
>>> import tempfile
>>> file = tempfile.NamedTemporaryFile(mode='a')
>>> example = file.name
>>> f.close()
>>> import subprocess
>>> subprocess.call(['nano', example])
Now once the last line gets executed the file gets open and I can write anything and then save it by hitting Ctrl+O and Ctrl+X
Instead I want that I send the input through a stdin PIPE and and the file gets saved by itself ie there could be any mechanism that hits Ctrl+O and Ctrl+X automayically by itself ?
Can help me in solving this issue ?
A ctrl-O is just a character, same as any other. You can send it by writing '\x0f' (or, in Python 3, b'\x0f').
However, that probably isn't going to do you any good. Most programs that provide an interactive GUI in the terminal, like nano, cannot be driven by stdin. They need to take control of the terminal, and to do that, they will either check that stdin isatty and then tcsetattr it, or just open /dev/tty,
You can deal with this by creating a pseudo-terminal with os.openpty, os.forkpty, or pty.
But it's often easier to use a library like pexpect to deal with interactive programs, GUI or otherwise.
And it's even easier to not try to drive an interactive program in the first place. For example, unlike nano, ed is designed to be driven in "batch mode" by a script, and sed even more so.
And it's even easier to not try to drive a program at all when you're trying to do something that can be just as easily done directly in Python. The easiest way to append something to a file is to open it in 'a' mode and write to it. No need for an external program at all. For example:
new_line = input('What do you want to add?')
with open(fname, 'a') as f:
f.write(new_line)
If the only reason you were using nano is because you needed something to sudo… there's really no reason for that. You can sudo anything else—like sed, or another Python script—just as easily. Using nano is just making things harder for yourself for absolutely no reason.
The big question here is: why do you have a file that's not writable by your Python script, but which you want arbitrary remote users to be able to append to? That sounds like a very bad system design. You make files non-writable because you want to restrict normal users from modifying them; if you want your Python script to be able to modify it on behalf of your remote users, why isn't it owned by the same user that the script runs as?
In the (unlikely) event that you still find that you need to control nano or some other interactive program from a Python process, I'm going to suggest the same thing here that I suggested for this question: Using python subprocess.call() to launch an ncurses process ...
... don't use subprocess for controlling curses/full-screen interactive processes. use pexpect. That's what it's for.
(On the other hand I also agree with the many comments here regarding better ways to work around the permissions issue. Write some sort of script (in Python, bash, sed or whatever) which can be run under sudo and which can make the in-place edits or appendices to your data file directly.

Running subprocess commands as root in python

I'm writing a GUI program, that configures your systems settings. For this purpose, the whole program should not be ran as root, otherwise it would configure the system for the root user. However, there is a subprocess command that needs to be ran as root, and I'm not sure how to safely, and properly incorporate this into my GUI for the following reasons.
The user would almost have to enter it into the GUI frontend.
I'm not sure how to verify that the users password was indeed correct. How to add error proofing to alert the user that the password is incorrect, without just letting the command fail miserably.
How to run this safely, since the users password is going to be involved.
I've been reccomended to create a daemon, and pass commands to that. This seems like a bit overkill, since it's just one command that needs to be ran. And since the user can't just type this into the terminal, it needs to be handled by the frontend of the GUI.
Does anyone have any other ideas on how to incorporate this feature?
You can use pkexec.
For example:
proc = subprocess.Popen(['/usr/bin/pkexec', command])

python subprocess terminal mac osx

longtime lurker, first time poster.
I know there are quite a few examples throughout the interweb on using subprocess, however I am yet to find one that explains the steps I need to take to birth a new terminal window, and send it commands. There are plenty of posts that give workarounds to launch tools and scripts via a direct subprocess call, but I have not found any that actually answer the original questions of how to send a command properly to terminal.
In my case, I need to open a new terminal window, then send the path to a particular version of an application, and finally the path to the file I wish to open in that application.
I know how to use subprocess to call the applications needed directly (without opening a visible terminal), how to open a new terminal with subprocess, and how to call either the application path OR the file path (have not been able to get both to execute together using --args for open() or any other workaround I have found).
I have been unable to send terminal a command once I have opened it. The following is a simple version of opening a new instance of terminal and sending it ls, which does not work.
from subprocess import Popen, PIPE, STDOUT
p = Popen(['open', '-a', 'Terminal', '-n'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
output = p.communicate(input='ls')
print(output)
This is most likely a trivial issue and I am simply missing something, but I have been unable to find the information or an example that illustrates what I need and I am beginning to get frustrated with it, so I figured I would ask for help.
Any assistance is greatly appreciated! TIA
First, I doubt that command you are trying to run will run at all.
Did you try it in terminal first? open -an Terminal will give you
an error. It probably should be something like open -n
/Applications/Utilities/Terminal.app
Second, #korylprince is right: open itself will create new process
of Terminal and exit. So you are linking pipe with wrong process.
Third, at the moment of passing ls to the stdin that process
doesn't exist already (unless you will pass -W option to the open,
but it certainly will not help due to the 2 problem).
So I see only one opportunity to do this: via AppleScript. You can create an AppleScript string, something like next:
tell application "System Events"
tell process "Terminal"
keystroke "ls"
keystroke return
end tell
end tell
and then run this script via osascript -e '<your_script>' via Popen.
Yes it is quite tricky (I'd say it is a hack)
Yes there probably will be problems with passing multiline string to Popen and with determining correct Terminal window.
But it is possible.
#cody
My response to your answer was too long, therefore I am making an answer to respond:
You are correct, if you enter it the way you offered, it flags an error, and if you put the -n before Terminal it still flags an error. However, if you enter it the way I showed in the first example (-n after Terminal) "open" calls a new instance of app bundle Terminal, even if one is already open.
As for 2-3, that was kind of what my research was leading me to believe, but I was hoping I was wrong or missed something somewhere and someone here could clarify. Sadly, I wasn't mistaken…
I should probably expand on what I am trying to do, as maybe it will help generate a better way to accomplish it via Python.
I have created a tool that launches application files based on the movie, scene, and shot an artist is working on. For some applications, like Nuke and Houdini, opening from Terminal gives you a wealth of information that the artist would be blind to otherwise, so we would like to give the artist the option to launch the file they have chosen in a Terminal. That terminal has to be standalone, and a new instance of Terminal, because the app I have created must persist after the launch in order to open other shots in different applications without making the user routinely open the app.
Parsing the necessary info, building the commands, and launching a new Terminal that launches the desired application were all trivial. Doing the same with the desired file was trivial as well. The issue arises when a particular version of the app is chosen, and I have not been able to pass the newly birthed instance of Terminal with more than a single command (honestly the syntax of my OSX command may be the issue as well, will post further down).
I can get the following two commands to work without issue:
p = Popen(['open', '-a', 'Terminal', '-n', '--args', '/Applications/Nuke6.3v8/Nuke6.3v8.app/Nuke6.3v8'])
p = Popen(['open', '-a', 'Terminal', '-n', '--args', '/Path/to/Nuke/File.nk'])
I cannot get the following to work properly:
p = Popen(['open', '-a', 'Terminal', '-n', '--args', '/Applications/Nuke6.3v8/Nuke6.3v8.app/Nuke6.3v8', '/Path/to/Nuke/File.nk'])
From there my thought was possibly that I should launch the Terminal in the Popen, then pass the commands I needed. That did not work, and then I came here lol
Thanks again for any help! Just knowing that I cannot send to the commands I want to Terminal is saving me a ton of time that would have been spent on continuos frustrated research.

subprocess.call does not wait for the process to complete

Per Python documentation, subprocess.call should be blocking and wait for the subprocess to complete. In this code I am trying to convert few xls files to a new format by calling Libreoffice on command line. I assumed that the call to subprocess call is blocking but seems like I need to add an artificial delay after each call otherwise I miss few files in the out directory.
what am I doing wrong? and why do I need the delay?
from subprocess import call
for i in range(0,len(sorted_files)):
args = ['libreoffice', '-headless', '-convert-to',
'xls', "%s/%s.xls" %(sorted_files[i]['filename'],sorted_files[i]['filename']), '-outdir', 'out']
call(args)
var = raw_input("Enter something: ") # if comment this line I dont get all the files in out directory
EDIT It might be hard to find the answer through the comments below. I used unoconv for document conversion which is blocking and easy to work with from an script.
It's possible likely that libreoffice is implemented as some sort of daemon/intermediary process. The "daemon" will (effectively1) parse the commandline and then farm the work off to some other process, possibly detaching them so that it can exit immediately. (based on the -invisible option in the documentation I suspect strongly that this is indeed the case you have).
If this is the case, then your subprocess.call does do what it is advertised to do -- It waits for the daemon to complete before moving on. However, it doesn't do what you want which is to wait for all of the work to be completed. The only option you have in that scenario is to look to see if the daemon has a -wait option or similar.
1It is likely that we don't have an actual daemon here, only something which behaves similarly. See comments by abernert
The problem is that the soffice command-line tool (which libreoffice is either just a link to, or a further wrapper around) is just a "controller" for the real program soffice.bin. It finds a running copy of soffice.bin and/or creates on, tells it to do some work, and then quits.
So, call is doing exactly the right thing: it waits for libreoffice to quit.
But you don't want to wait for libreoffice to quit, you want to wait for soffice.bin to finish doing the work that libreoffice asked it to do.
It looks like what you're trying to do isn't possible to do directly. But it's possible to do indirectly.
The docs say that headless mode:
… allows using the application without user interface.
This special mode can be used when the application is controlled by external clients via the API.
In other words, the app doesn't quit after running some UNO strings/doing some conversions/whatever else you specify on the command line, it sits around waiting for more UNO commands from outside, while the launcher just runs as soon as it sends the appropriate commands to the app.
You probably have to use that above-mentioned external control API (UNO) directly.
See Scripting LibreOffice for the basics (although there's more info there about internal scripting than external), and the API documentation for details and examples.
But there may be an even simpler answer: unoconv is a simple command-line tool written using the UNO API that does exactly what you want. It starts up LibreOffice if necessary, sends it some commands, waits for the results, and then quits. So if you just use unoconv instead of libreoffice, call is all you need.
Also notice that unoconv is written in Python, and is designed to be used as a module. If you just import it, you can write your own (simpler, and use-case-specific) code to replace the "Main entrance" code, and not use subprocess at all. (Or, of course, you can tear apart the module and use the relevant code yourself, or just use it as a very nice piece of sample code for using UNO from Python.)
Also, the unoconv page linked above lists a variety of other similar tools, some that work via UNO and some that don't, so if it doesn't work for you, try the others.
If nothing else works, you could consider, e.g., creating a sentinel file and using a filesystem watch, so at least you'll be able to detect exactly when it's finished its work, instead of having to guess at a timeout. But that's a real last-ditch workaround that you shouldn't even consider until eliminating all of the other options.
If libreoffice is being using an intermediary (daemon) as mentioned by #mgilson, then one solution is to find out what program it's invoking, and then directly invoke it yourself.

Categories

Resources