Start Python scripts with launchctl (OSX)

724 Views Asked by At

I have a very simple test scrip that I want my computer to run every 60 seconds - time_test_script.py. The script simply saves a .txt file with current time as name and writes some text onto the file. The file is in /Users/me/Documents/Python dir.

import datetime
import os.path
path = '/Users/me/Desktop/test_dir'
name_of_file = '%s' %datetime.datetime.now()
completeName = os.path.join(path, name_of_file+".txt")
file1 = open(completeName, "w")
toFile = 'test'
file1.write(toFile)
file1.close()
print datetime.datetime.now()

I also have a .plist file – test.plist that is in /Library/LaunchAgents dir.

test.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.test</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/me/Documents/Python/time_test_script.py</string>
    </array>
    <key>StartInterval</key>
    <integer>60</integer>
</dict>
</plist>

If I run the script manually it works fine, i.e. is creates a .txt file in the specified directory. However, when I try to initiate launchctl from the Terminal nothing happens.

 $ launchctl load /Library/LaunchAgents/test.plist 
 $ launchctl start com.test

What am I doing wrong?

2

There are 2 best solutions below

0
On

If you are running a script without using python scriptname.py, then the script needs to be marked executable (chmod a+x scriptname.py from the command line) and the first line should tell the system which interpreter to use, which in this case will be #!/usr/bin/python.

For example:

Sapphist:~ zoe$ cat >test.py
print "Hello World"
Sapphist:~ zoe$ ./test.py
-bash: ./test.py: Permission denied

With just the execute bit set:

Sapphist:~ zoe$ cat >test.py
print "Hello World"

Sapphist:~ zoe$ chmod a+x test.py
Sapphist:~ zoe$ ./test.py
./test.py: line 1: print: command not found

With both an interpreter and execute bit:

Sapphist:~ zoe$ cat >test.py
#!/usr/bin/python
print "Hello World!"

Sapphist:~ zoe$ chmod a+x test.py
Sapphist:~ zoe$ ./test.py
Hello World!
Sapphist:~ zoe$
0
On

First argument in ProgramArguments must be your python interpreter.

(used a pyenv interpreter as example)

Also add the workingdirectory to something because it defaults to / which is readonly.

    <key>ProgramArguments</key>
    <array>
        <string>/Users/me/.pyenv/versions/timetest/bin/python</string>
        <string>/Users/me/Documents/Python/time_test_script.py</string>
    </array>
    <key>WorkingDirectory</key>
        <string>/Users/me/Documents/Python</string>

for debugging sudo launch list com.test will help you:

(example from one of my own services)

if ExitStatus!=0 and PID missing something may be wrong.

{
    "StandardOutPath" = "/var/log/gitlab.mobj.board.log";
    "LimitLoadToSessionType" = "System";
    "StandardErrorPath" = "/var/log/gitlab.mobj.board.log";
    "Label" = "gitlab.mobj.board";
    "OnDemand" = false;
    "LastExitStatus" = 0;
    "PID" = 312;
    "Program" = "/Users/mobj/.pyenv/versions/gitlab-mobj-board/bin/python";
    "ProgramArguments" = (                
        "/Users/mobj/.pyenv/versions/gitlab-mobj-board/bin/python";
        "/dist/gitlab-mobj-board/main.py";        
    );
};