Calling Maxima files from Python Script - python

EDIT: It turns out the shell that the subprocess module does not have the same directories assigned to the PATH variable as my system's shell. Thus the solution is simply to either call Maxima using the full path (found through which maxima) or changing env={'PATH':maxima_paths} in the subprocess.run() parameters. As #RobertDodier pointed out, this is not an issue with Maxima specifically.
I have a file called testMaxima.txt that contains the following Maxima code:
write_data([[1,2,3]], "test.txt");
This Maxima code creates the file test.txt in the working directory.
I am looking to run this file using a Python script. I do not want to open Maxima (a math engine) manually in order to do this.
What I've tried: I know that I can run this file in Command Line/Terminal using maxima -b testMaxima.txt and I have tried to use the python module subprocess to emulate this code with the following python code:
import subprocess
subprocess.run("maxima -b testMaxima.txt", shell=True)
but this does not create the new test.txt file like it should. If this helps, when I run
>>> subprocess.call("maxima -b testMaxima.txt", shell=True)
127
I get an output of 127. From what I understand, this means that the terminal can't find the given commands. However, there is no issues when I execute the code maxima -b testMaxima.txt through the terminal directly, so I'm not sure why it cannot find the given commands. Does anyone have any thoughts on what I should try?
Thank you in advance!
EDIT: From #mkrieger 's advice, I am using a string "maxima -b testMaxima.txt" instead of the sequence ["maxima", "-b", "testMaxima.txt"]. Unfortunately, this does not make a difference.

how about using os.system in python.
import os
os.system('maxima -b testMaxima.txt')
Also make sure that you are running this python script in the location where testMaxima.txt file is present

Related

Create python script to run terminal command with source

Long story short, I'm trying to figure out a way to turn these command lines into a script or function in python that can be called by another python application.
These are the command lines in Linux:
source tflite1-env/bin/activate
python3 stream.py --modeldir=TFLite_model
At first I was like this will be easy its just launching the application in python - but I'm not really sure how to deal with the source part. I thought it was just accessing the directory, but its doing something with the .csh file...
I tried a very convoluted method by creating a .sh file like so:
#!/bin/bash
cd ..
cd tflite1
source tflite1-env/bin/activate
python3 stream.py --modeldir=TFLite_model
and then making a function for my main program to call said file:
import os
def startCamera():
os.system('sh script.sh')
With this method I get an error about the source not being found.
I think the issue is I'm basically trying to call too many separate processes that are terminating each other or something? There's got to be a better way. Any suggestions would be greatly appreciated!
I changed the function to:
import subprocess
def startTheCamera()
subprocess.call("/home/pi/Desktop/launchCamera.sh")
I used subprocess instead of os.system and included the full file path and it works now. I think maybe it only needed the full file path, even though it was all in the same directory.

Run terminal script in python?

I am using python and I am trying to run a shell script that is located in another folder I am trying
subprocess.call(['source','../Apps/appName/run'])
Where 'run' is a shell script I wrote and made an executable. But it keeps giving errors such as
No such file or directory or **No such file or directory: "source"
I have also tried the following
subprocess.call(['source','../Apps/appName/run'])
subprocess.call(['source ../Apps/appName/run'])
subprocess.call(['.','../Apps/appName/run'])
I am trying to run the script and leave it alone (as in I do not want any return value or to see what the output of the shell script is.
Thank you in advance
source is a shell builtin that reads a file and interprets the commands in the current shell instance. It's similar to C #include or Python import. You should not be using it to run shell scripts.
The correct way to run a script is to add a shebang like #!/bin/bash to the first line, and chmod +x yourscriptfile. The OS will then consider it a real executable, which can be executed robustly from any context. In Python, you would do:
subprocess.call(['../Apps/appName/run'])
If for whichever reason this is not an option, you can instead explicitly invoke bash on the file, since this is similar to what would happen if you're in bash and type source:
subprocess.call(['bash', '../Apps/appName/run'])

How to retrieve a filename and file created using a shell script that was called from a python script?

I have a python script that calls a shell script. The shell script captures an image, names the image using a timestamp, and then saves the image to directory. When the shell script finishes, I would like to access the image from the python script that called the shell script.
Here is my shell script capture.sh:
DATE=$(date +"%Y-%m-%d_%H%M%S")
fswebcam -r 1280x720 --no-banner /home/pi/app/images/$DATE.jpg
exit 0
This shell script is called from capture.py:
import os
import subprocess
# call script
subprocess.call(['/home/pi/app/capture.sh'])
#?how to retrieve and process image: /home/pi/app/images/$DATE.jpg
Any advice would be welcome! Thank you!
You can send the name of the file created by the bash script to standardout and capture that in the python script. Here is a similar SO question that I think will lead you in the right direction.
As the top answer to this question points out, it will depend on what version of python you're doing this work in. It looks like you're using subprocess.call. In terms of the current python docs for subprocess, that is the old API call. You can now use subprocess.run in versions 3.5 and newer, which is the recommended way to invoke child processes.
Running shell command and capturing the output

Execute bash script from Python on Windows

I am trying to write a python script that will execute a bash script I have on my Windows machine. Up until now I have been using the Cygwin terminal so executing the bash script RunModels.scr has been as easy as ./RunModels.scr. Now I want to be able to utilize subprocess of Python, but because Windows doesn't have the built in functionality to handle bash I'm not sure what to do.
I am trying to emulate ./RunModels.scr < validationInput > validationOutput
I originally wrote this:
os.chdir(atm)
vin = open("validationInput", 'r')
vout = open("validationOutput", 'w')
subprocess.call(['./RunModels.scr'], stdin=vin, stdout=vout, shell=True)
vin.close()
vout.close()
os.chdir(home)
But after spending a while trying to figure out why my access was denied, I realized my issue wasn't the file permissions but the fact that I was trying to execute a bash file on Windows in general. Can someone please explain how to execute a bash script with directed input/output on windows using a python script?
Edit (Follow up Question):
Thanks for the responses, I needed the full path to my bash.exe as the first param. Now however, command line calls from within RunModels.scr come back in the python output as command not found. For example, ls, cp, make. Any suggestions for this?
Follow up #2:
I updated my call to this:
subprocess.call(['C:\\cygwin64\\bin\\bash.exe', '-l', 'RunModels.scr'], stdin=vin, stdout=vout, cwd='C:\\path\\dir_where_RunModels\\')
The error I now get is /usr/bin/bash: RunModels.scr: No such file or directory.
Using cwd does not seem to have any effect on this error, either way the subprocess is looking in /usr/bin/bash for RunModels.scr.
SELF-ANSWERED
I needed to specify the path to RunModels.scr in the call as well as using cwd.
subprocess.call(['C:\\cygwin64\\bin\\bash.exe', '-l', 'C:\\path\\dir_where_RunModels\\RunModels.scr'], stdin=vin, stdout=vout, cwd='C:\\path\\dir_where_RunModels\\')
But another problem...
Regardless of specifying cwd, the commands executed by RunModels.scr are throwing errors as if RunModels.scr is in the wrong directory. The script executes, but cp and cd throw the error no such file or directory. If I navigate to where RunModels.scr is through the command line and execute it the old fashioned way I don't get these errors.
Python 3.4 and below
Just put bash.exe in first place in your list of subprocess.call arguments. You can remove shell=True, that's not necessary in this case.
subprocess.call(['C:\\cygwin64\\bin\\bash.exe', '-l', 'RunModels.scr'],
stdin=vin, stdout=vout,
cwd='C:\\path\\dir_where_RunModels\\')
Depending on how bash is installed (is it in the PATH or not), you might have to use the full path to the bash executable.
Python 3.5 and above
subprocess.call() has been effectively replaced by subprocess.run().
subprocess.run(['C:\\cygwin64\\bin\\bash.exe', '-l', 'RunModels.scr'],
stdin=vin, stdout=vout,
cwd='C:\\path\\dir_where_RunModels\\')
Edit:
With regard to the second question, you might need to add the -l option to the shell invocation to make sure it reads all the restart command files like /etc/profile. I presume these files contain settings for the $PATH in bash.
Edit 2:
Add something like pwd to the beginning of RunModels.scr so you can verify that you are really in the right directory. Check that there is no cd command in the rc-files!
Edit 3:
The error /usr/bin/bash: RunModels.scr: No such file or directory can also be generated if bash cannot find one of the commands that are called in the script. Try adding the -v option to bash to see if that gives more info.
A better solution than the accepted answer is to use the executable keyword argument to specify the path to your shell. Behind the curtain, Python does something like
exec([executable, '-c`, subprocess_arg_string])
So, concretely, in this case,
subprocess.call(
'./RunModels.scr',
stdin=vin, stdout=vout,
shell=True,
executable="C:/cygwin64/bin/bash.exe")
(Windows thankfully lets you use forward slashes instead of backslashes, so you can avoid the requirement to double the backslashes or use a raw string.)

run imposm commands from a python script

I'm just getting started using imposm to help get openstreetmap data into a postgis database. All the docs point to making all commands via Terminal. This is fine for one off imports but I plan to have many many imports of varying bounding boxes and would like to script the loading of the data in the database.
Currently I use:
imposm --overwrite-cache --read --write -d postgis_test --user postgres -p "" /Users/Me/MapnikTest/osmXML.osm
Which works fine from the command line but as osmXML.osm is being created many times I would like somehow to import this at the point of creation.
Putting the same thing in a python script as:
os.system("imposm --overwrite-cache --read --write -d postgis_test --user postgres -p "" /Users/Ali\ Mac\ Pro/Desktop/MapnikTest/osmXML.osm")
just returns:
/bin/sh: imposm: command not found
Solving this would be the final step to automate the acquisition of data to render small maps on demand but I'm falling at the final hurdle!
** Edit full path to imposm solved the first problem but imputing the password for the postgres user happens when prompted. Is there a way to send the password in the same single line command? (maybe this needs to be a new post?, happy if someone points me in the right direction)**
This is probably because os.system() is calling /bin/sh which uses a different shell environment from the one you use when working on the command line.
To work around this, in your script, get the full path to the imposm script and then use that in your command. Use can use some code like this to find the executable.
Or you can fix your shell definitions so that /bin/sh has the proper PATH defined, but that depends greatly on your setup...
Solved with the help of further research and the comments from #Eli Rose (many thanks): find out what path to imposm (or whichever command you are trying to make) with
which <command>
Then include the path in the python shell command. Using a module from subprocess you can even see the full terminal output.
import subprocess
from subprocess import *
print Popen("/usr/local/bin/imposm --overwrite-cache --read --write --connection postgis://<database user>:<password>#<host>/<database> /path/to/data.osm", stdout=PIPE, shell=True).stdout.read()
The
--connection postgis://<database user>:<password>#<host>/<database>
means you can make the command in a single line and not have to worry about entering the database user password in a following command.

Categories