I found a work around when calling a python script from a shell script from automator (version 2.1.1 in mac os x 10.6.8) (python 2.6.1). My issue is that os.system("mkdir foo") works in a (very specific) case where subprocess.call("mkdir foo") also makes the directory but then makes automator throw an error.
The purpose of my automator app is to accept an image that is dragged-and-dropped onto it.
The automator app has just one action: 'run shell script' with the following code:
for f in "$#"
do
python dphoto_pythons/uploader.py $f > dphoto_pythons/auto_output.txt
done
$f is the name of the dragged image. ('Run shell script' is set to pass input as arguments.)
Here is the strange part:
in the 'uploader.py' script, I was calling this:
retcode=call("mkdir " + dir_full, shell=True) # THIS CAUSES A ERROR IN AUTOMATOR
print "***DOESN'T GET HERE WHEN RUN IN AUTOMATOR****"
It makes the directory. but doesn't get to the next statement. And automator would throw up an error dialog (which just says that I should go check my script).
By contrast, if I called uploader.py 'manually' from the terminal:
"python uploader.py someimage.jpg"
it worked without a hitch.
After puzzling over this for a bit, I tried replacing call with os.system:
os.system("mkdir " + stu_dir_full)
####retcode=call("mkdir " + stu_dir_full, shell=True) # BUG
This works from automator and from terminal.
I have a feeling that I'm over-looking something obvious because this is such a bizarre problem. But thought I'd put this out there in any case. Any thoughts?
-Mel
You could use os.mkdir(stu_dir_full)...
But the problem with your subprocess.call line might be that subprocess.call is expecting a list not a string. Try this:
retcode = call(["mkdir",dir_full], shell=True)
Related
Ok, so I'm making a sort of Python middle man. Basically, it takes user input and throws it at Command Prompt, and then returns the output. Here's the code.
import os
console=True
while console==True:
command=input(">")
os.system(command)
The issue is that directory navigation does not seem to be working. The following is what happens when I use the cd command.
>cd
C:\Users\Username\Desktop\Stuff
>cd ..
>cd
C:\Users\Username\Desktop\Stuff
Any ideas?
the problem is that when you execute the cd command it is executed in another context, it is another independent process because your main process never changes directory. you should use the os.chdir (path) method
Changing working directory cannot be done via external commands. You have to parse the command line by yourself:
command = input("> ")
cmd = command.split()
if cmd[0] == "cd":
os.chdir(cmd[1])
Of course, the above code is only an example because the use of str.split() is too wild. You need to take care of quotes and escaped spaces if you want a fully working "shell".
I want to execute which jupyter command in Python code in order to receive location of my jupyter binary file.
My Python script named ReportGenerator.py looks as follow:
from subprocess import call
if __name__ == "__main__":
call(["which", "jupyter"])
output is:
But if I navigate to the same folder in terminal and execute code Python script then:
Kamils-MacBook-Pro-2:project F1sherKK$ python3 ReportGenerator.py
/Users/F1sherKK/.pyenv/versions/3.6.1/bin/jupyter
It works... so I made sure my PyCharm IDE is using the same python 3.6.1 as my terminal. I am not using any virtualenv at the moment.
Can somebody explain why this happens?
subprocess.call() executes the given command and returns the command's return code (0 => ok, anything else is an error).
The interactive Python shell (whether embedded in your IDE or not) displays the stdout and stderr streams of the command as well as the return code, but this is only an artifact of the interactive Python shell - as you noticed this will not print anything to stdout if you run the same code as a script.
Here you want to use subprocess.check_output() instead, which will return the command's output as a string. Then you need to explicitely print this string to your python's process stdout:
import subprocess
if __name__ == "__main__":
found = subprocess.check_output(["which", "jupyter"])
print(found)
I don't know why it happens, but here is what I use for a code that runs both from console and from cron:
def which(name):
'''
Replace unix 'which' command.
Tested on windows10 and linux mint. Should work on all platforms.
:param name: Requested command name
:type name: str
:return: Full path to command
:rtype: str
'''
for path in os.getenv("PATH").split(os.path.pathsep):
full_path = path + os.sep + name
if os.path.exists(full_path) and os.access(full_path, os.X_OK):
return full_path
raise ValueError('Cant fint command %s')%name
EDIT:
On windows, the function will return value on non-executable files.
For writing your own solution for windows see: descusion
When I manually run this command in Terminal, it executes, but through Python it gives the error that the directory is not available in Python packages.
I am using the following command
source ~/trytry/shell.sh
This is my test shell file:
#!/bin/sh
echo hello
when I executed " source ~/test.sh ", it will print hello at console.
This is my python code:
>>> import commands
>>> commands.getstatusoutput("source ~/test.sh")
(0, 'hello')
It works without any problem. So, would you please show your code?
What it looks like to me is that you have a shell script, and not a python file which would have the .py extension instead of .sh. The error may have to do with the fact that it isn't a python file you're trying to run.
I can run one program by typing: python enable_robot.py -e in the command line, but I want to run it from within another program.
In the other program, I imported subprocess and had subprocess.Popen(['enable_robot', 'baxter_tools/scripts/enable_robot.py','-e']), but I get an error message saying something about a callback.
If I comment out this line, the rest of my program works perfectly fine.
Any suggestions on how I could change this line to get my code to work or if I shouldn't be using subprocess at all?
If enable_robot.py requires user input, probably it wasn't meant to run from another python script. you might want to import it as a module: import enable_robot and run the functions you want to use from there.
If you want to stick to the subprocess, you can pass input with communicate:
p = subprocess.Popen(['enable_robot', 'baxter_tools/scripts/enable_robot.py','-e'])
p.communicate(input=b'whatever string\nnext line')
communicate documentation, example.
Your program enable_robot.py should meet the following requirements:
The first line is a path indicating what program is used to interpret
the script. In this case, it is the python path.
Your script should be executable
A very simple example. We have two python scripts: called.py and caller.py
Usage: caller.py will execute called.py using subprocess.Popen()
File /tmp/called.py
#!/usr/bin/python
print("OK")
File /tmp/caller.py
#!/usr/bin/python
import subprocess
proc = subprocess.Popen(['/tmp/called.py'])
Make both executable:
chmod +x /tmp/caller.py
chmod +x /tmp/called.py
caller.py output:
$ /tmp/caller.py
$ OK
I'm writing a python (ver 2.7) script to automate the set of commands in this Getting Started example for INOTOOL.
Problem: When I run this entire script, I repeatedly encounter these errors:
Current Directory is not empty
No project is found in this directory
No project is found in this directory
But, when I run a first script only up till the code line marked, and manually type in the next three lines, or when I run these last three lines (starting from the "ino init -t blink" line) after manually accessing the beep folder, then I am able to successfully execute the same code.
Is there a limitation with os.system() that I'm encountering?
My code:
import os,sys
def upload()
os.system("cd /home/pi/Downloads")
os.system("mkdir beep")
os.system("cd beep") #will refer to this code junction in question description
os.system("ino init -t blink")
os.system("ino build")
os.system("ino upload")
sys.exit(0)
Yes, when os.system() commands are run for cd , it does not actually change the current directory for the python process' context. From documentation -
os.system(command)
Execute the command (a string) in a subshell. This is implemented by calling the Standard C function system(), and has the same limitations. Changes to sys.stdin, etc. are not reflected in the environment of the executed command.
So even though you are changing directory in os.system() call, the next os.system call still occurs in same directory. Which could be causing your issue.
You shoud try using os.chdir() to change the directory instead of os.system() calls.
The Best would be to use subprocess module as #PadraicCunningham explains in his answer.
You can use the subprocess module and os.mkdir to make the directory, you can pass the current working directory cwd to check_callso you actually execute the command in the directory:
from subprocess import check_call
import os
def upload():
d = "/home/pi/Downloads/beep"
os.mkdir(d)
check_call(["ino", "init", "-t", "blink"],cwd=d)
check_call(["ino", "build"],cwd=d)
check_call(["ino", "upload"],cwd=d)
A non-zero exit status will raise CalledProcessError which you may want to catch but once successful you know the commands all returned a 0 exit status.