Running Mac application in same thread as parent script - python

Very specific question: I am writing a (Python) script that should
generate a temporary file.
Launch an image viewer.
Upon closing the viewer, deletes the tmp file.
In linux, this would work fine because I'd open a subprocess from Python and run the following
eog myimg.png; rm myimg.png
However, the story is different on Mac. The open command launches in a different process. If I use /Applications/Preview.app/MacOS/Preview, I get a weird permissions issue. This persists if I kill my script, leaving the file, then fire up Terminal.app:
Running open myimg.png works as expected. Running /Applications/Preview.app/MacOS/Preview myimg.png gets the same permissions error. (Meaning to say- it's not actually a file permissions error). And FWIW, the file is 444 anyway.
My guess is that the open command runs applications from a different user, which is allowed to access parent directories that my user is not using, something like that.
Anyway, anyone know exactly what's going on, and what a viable solution would be? Thank you!
EDIT
Current code is
name = '/var/folders/qy/w9zq1h3d22ndc2d_7hgwj2zm0000gn/T/tmpDHRg2T.png'
viewer_command = 'open'
subprocess.Popen(viewer_command + ' ' + name +' ; rm ' + name, shell=True)

Anyway, anyone know exactly what's going on, and what a viable solution would be?
It's hard to say for certain without more details (like how your script is being run, and what error message you are getting), but it seems likely that your script is either running as a different user from the console user, or is not running within the login context.
Contexts are an unusual feature of Mac OS X, and are documented in Apple's Kernel Programming Guide ("Bootstrap Contexts"). In brief, a process that is not launched from a process descended from the login window (for instance, a process that is launched through SSH) will not have the necessary access to services within that context, such as the WindowServer, to start a desktop application.

#!/bin/sh
TMP=$(mktemp sperry.XXXXXX.jpg)
echo "Made $TMP"
IMG="/Users/sean_perry/Pictures/Photo Booth Library/Pictures/Photo on 6-8-12 at 4.37 PM.jpg"
cp "$IMG" $TMP
open "$TMP"
rm $TMP
This script works just fine on my OSX machine.
So does
#!/usr/bin/python
import subprocess
subprocess.call(["open", "/Users/me/Pictures/Photo Booth Library/Pictures/Photo on 6-8-12 at 4.37 PM.jpg"])
Can you post yours?

Related

adding magnet links from cron job

I have a piece of python script which puts magnet links in transmission. Now when I run it through terminal it runs ok, opens transmission if closed and adds the torrent/s. Now when I put it in a cron, transmission doesn't open but I know that the cron is running because it writes to a text file the name of the file which is being added.
def download_movie(magnet_link):
os.system('transmission-gtk ' + magnet_link)
As you can see the code is pretty simple and just invokes transmission and passes the magnet link. Thank you.
Altough resons for this may vary, what solved the issue for me most times was logging in as superuser and then do the cron.
If that does not work additional information would be needed, so consider also posting the log. It should be in /var/log/syslog.
What might help, too is setting an absolute path for python: Instead of python write the full path, normally /usr/bin/python+yourVersionNumber
If the script is really simple you could write the code in bash, it would be something like this...
magnetlink=`cat file.txt | cut -d ' ' -f1`
echo "magnetlink" | transmission-gtk
Like #frankenapps said you could try adding the code to:
sudo crontab -e

Python Thread Breaking Terminal

Hello minds of stackoverflow,
I've run into a perplexing bug. I have a python script that creates a new thread that ssh's into a remote machine and starts a process. However, this process does not return on its own (and I want it to keep running throughout the duration of my script). In order to force the thread to return, at the end of my script I ssh into the machine again and kill -9 the process. This is working well, expect for the fact that it breaks the terminal.
To start the thread I run the following code:
t = threading.Thread(target=run_vUE_rfal, args=(vAP.IP, vUE.IP))
t.start()
The function run_vUE_rfal is as follows:
cmd = "sudo ssh -ti ~/.ssh/my_key.pem user#%s 'sudo /opt/company_name/rfal/bin/vUE-rfal -l 3 -m -d %s -i %s'" % (vUE_IP, vAP_IP, vUE_IP)
output = commands.getstatusoutput(cmd)
return
It seems when the command is run, it somehow breaks my terminal. It is broken in that instead of creating a new line for each print, it appends the WIDTH of my terminal in whitespace to the end of each line and prints it as seemingly one long string. Also, I am unable to see my keyboard input to that terminal, but it still successfully read. My terminal looks something like this:
normal formatted output
normal formatted output
running vUE-rfal
print1
print2
print3_extra_long
print4
If I replace the body of the run_vUE_rfal function with some simple prints, the terminal does not break. I have many other ssh's and telnets in this script that work fine. However, this is the only one I'm running in a separate thread as it is the only one that does not return. I need to maintain the ability to close the process of the remote machine when my script is finished.
Any explanations to the cause and idea for a fix are much appreciated.
Thanks in advance.
It seems the process you control is changing terminal settings. These are bypassing stderr and stdout - for good reasons. E.g. ssh itself needs this to ask users for passwords even when it's output is being redirected.
A way to solve this could be to use the python-module pexpect (it's a 3rd-party library) to launch your process, as it will create its' own fake-tty you don't care about.
BTW, to "repair" your terminal, use the reset command. As you already noticed, you can enter commands. reset will set the terminal to default settings.

Launchd prevents script from changing desktop picture

I have a little script I'm working on to retrieve a new picture from http://reddit.com/r/wallpapers daily, and set that as my wallpaper. When I call the script from the command line, it works beautifully. But as soon as I try and setup a launch daemon it will save the picture, but the desktop does not change. I expect it has something to do with the scope, but I have no idea where to start.
Code:
SCRIPT = """/usr/bin/osascript<<END
tell application "Finder"
set desktop picture to POSIX file "%s"
end tell
END"""
file_path = /some/file/the/script/downloaded.jpg
subprocess.Popen(SCRIPT%file_path, shell=True)
You could be right about the reason, however I've seen strange things with "POSIX file" commands inside an application tell block of code. "POSIX file" is an applescript command. You will find it in the "standard additions" applescript dictionary not the Finder's applescript dictionary. As such it could be a problem when you tell the Finder to perform that command because the Finder doesn't know that command.
A general applescript rule is that you shouldn't tell an application to do something that's not in its applescript dictionary... strange things can happen if you do. And you have a strange thing happening so step 1 is to make sure your code is as clean as possible.
So here's something to try. As mentioned I'm just guessing because I've seen problems with this before so it's worth a shot. Try this as your applescript code.
set p to POSIX file "%s"
tell application "Finder" to set desktop picture to p

python,running command line servers - they're not listening properly

Im attempting to start a server app (in erlang, opens ports and listens for http requests) via the command line using pexpect (or even directly using subprocess.Popen()).
the app starts fine, logs (via pexpect) to the screen fine, I can interact with it as well via command line...
the issue is that the servers wont listen for incoming requests. The app listens when I start it up manually, by typing commands in the command line. using subprocess/pexpect stops the app from listening somehow...
when I start it manually "netstat -tlp" displays the app as listening, when I start it via python (subprocess/pexpect) netstat does not register the app...
I have a feeling it has something to do with the environemnt, the way python forks things, etc.
Any ideas?
thank you
basic example:
note:
"-pz" - just ads ./ebin to the modules path for the erl VM, library search path
"-run" - runs moduleName, without any parameters.
command_str = "erl -pz ./ebin -run moduleName"
child = pexpect.spawn(command_str)
child.interact() # Give control of the child to the user
all of this stuff works correctly, which is strange. I have logging inside my code and all the log messages output as they should. the server wouldnt listen even if I started up its process via a bash script, so I dont think its the python code thats causing it (thats why I have a feeling that its something regarding the way the new OS process is started).
It could be to do with the way that command line arguments are passed to the subprocess.
Without more specific code, I can't say for sure, but I had this problem working on sshsplit ( https://launchpad.net/sshsplit )
To pass arguments correctly (in this example "ssh -ND 3000"), you should use something like this:
openargs = ["ssh", "-ND", "3000"]
print "Launching %s" %(" ".join(openargs))
p = subprocess.Popen(openargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
This will not only allow you to see exactly what command you are launching, but should correctly pass the values to the executable. Although I can't say for sure without seeing some code, this seems the most likely cause of failure (could it also be that the program requires a specific working directory, or configuration file?).

Mac OS X app/service and stdin?

I'm debugging a service I'm developing, which basically will open my .app and pass it some data to stdin. But it doesn't seem like it's possible to something like:
open -a myapp.app < foo_in.txt
Is it possible to pass stuff to an .app's stdin at all?
Edit:
Sorry, I should have posted this on SO and been more clear. What I'm trying to do is that I have an app made in Python + py2app. I want to be able to handle both when a user drops a file, and use it as a service. The first case isn't a problem since py2app has argv_emulation. I just check if the first argument is a path.
But reading from stdin doesn't work at all, it doesn't read any data regardless if I do as the example above or pipe it. If I pass stdin data to the actual python main script, it works. So I rephrase my question, is it possible to read from stdin with a py2app bundle?
What do you mean with using it as a service?
The example you show won't work, the open command calls LaunchServices to launch the application, and there is no place in the LaunchServices API to pass stdin data or similar to the application.
If you mean adding an item to the OS X Services Menu, you should look at the introductory documentation for developers.
Well,
open -a /Applications/myapp.app < foo_in.txt
will open foo_in.txt in your myapp.app application. You need the full path of the application, be it Applications, bin, or wherever it is...
It depends on what your application does. This may be more appropriate:
cat foo_in.txt | your_command_goes_here
That will read the contents of foo_in.txt (with cat) and pass them to stdin (with the pipe), so then you just follow that with your command / application.
To start Finder as root, one would not use:
sudo open -a /System/Library/CoreServices/Finder.app
The above runs open as root, but still open runs Finder as the normal user. Instead, one would use:
sudo /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder
So, following that, maybe (I am really just guessing) one needs:
myapp.app/Contents/MacOS/myapp < foo_in.txt
You should almost certainly be doing this through Mach ports or Distributed Objects or pretty much any other method of interapplication communication the OS makes available to you.
open creates an entirely new process. Therefore do not use it to redirect stuff into an application from Terminal.
You could try
./Foo.app/Contents/MacOS/Foo < Foo.txt
Already mentioned cat Foo.txt | ./Foo.app/Contents/MacOS/Foo very much depending on whether you set Foo as execurtbale and it's in your path. In your case I'd check the .app package for a Ressources folder, that may contain another binary.
A *.app Package is a directory. It cannot handle commandline arguments.

Categories