Launchd prevents script from changing desktop picture - python

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

Related

"sh: Error: Can't open display" when I try to start a program from python

I have this really strange problem, basically I want to start xpdf (or Libreoffice) from my Python script, that is started by a systemd-service. When I start the script from terminal everything is working fine, but when I plug in my USB device that start the Service, I'll get this Error in my syslog:
sh[2321]: Error: Can't open Display
This error has something to do with X11, that's what my Google searches tell me.
So, my question is: How can I properly run a program like xpdf or libreoffice from Python?
import subprocess
subprocess.call("/usr/bin/xpdf")
This is it, basically. I know that it has something to do with the graphical enviroment, but I don't know how I can solve it.
The X display system has very good security to stop random local processes from just displaying stuff to the local screen (It was more a problem in the old days of expensive Sun and SGI systems where computer labs would often let users telnet to other boxes. Much fun could be had!).
If the user running the xpdf is the same user as the one who's logged into the X session, then you simply need to tell xpdf where to connect it's UI to. This is usually done by exporting DISPLAY=:0 to the environment, which means "connect to the first local screen". Most X programs also support -display :0 argument.
So do:
/usr/bin/xpdf -display :0
or:
DISPLAY=:0 /usr/bin/xpdf
It's very unlikely that you have more than one X session so :0 will work 99% of the time.
Since the issue is that xpdf isn't finding a display to connect to, we have two basic options: find and authenticate with an existing display, or make a new one. The latter is usually easier, something like:
xinit /usr/bin/xpdf -fullscreen $PDFFILE -- :2
This would start a new X display :2 running only xpdf, not even a window manager.
It finally worked, after trying and going crazy for around 2 weeks.
What worked was
os.system("DISPLAY=:0 /usr/bin/xpdf)
I know that subprocess.call is the better way to call the program, but it doesn't seem to work right now.
I'll try the way that Yann suggested later on, but for now I'm just overwhelmed with joy that it just works.
Thank you all for your help, I really appreciate it!

Python launch external process in its own window on any platform?

I'm hoping this isn't a dupe. I've searched and searched and tried suggestions from many posts here, but so far I can't find what I'm looking for.
I have a Python 2.7 app which communicates via a second app via sockets. I would like to make it so that when the first Python app is launched, it automatically starts the second one.
The challenge is I'd really like the second app to pop up in its own console window with its own console logging. The catch is my app is used by people on different platforms, so I'd like something that's platform-independent, and so far all I have found that do this use platform-specific things. So I wonder, is this something that's even possible?
The closest thing I've found is to use subprocess.Popen, like this:
subprocess.Popen(['python', 'myscript.py'],
stdout=None,
stderr=None,
stdin=None)
(I know that I could use sys.executable instead of 'python', but in some cases the second app that needs to run won't be a Python app.)
Anyway the above works except that the output of the second app shows up co-mingled in the same window as the first app. I tried to shell=True to the args for Popen (and then I switched the args to a string as recommended in the Popen documentation), like this:
subprocess.Popen(['python myscript.py'],
stdout=None,
stderr=None,
stdin=None,
shell=True
)
The result of that (at least on my Mac) is the same as before. The second Python app starts, but its output is co-mingled into the existing console window instead of launching a new one. (And on Windows I can't get that to work at all. I just get an error that "python myscript.py" is not a valid command. Same result if I change the string to "python.exe myscript.py")
I don't need any communication between the apps since I already have everything I need via the sockets. (My app is a game controller engine that connects to an external media controller which could be Unity, Unreal, Python, etc.)
I tried various incarnations of the "old" ways, including os.spawn, os.system and a bunch of other things, but none of them give the behavior I'm hoping for. I also tried to use the subprocess convenience functions, but as far as I can tell those all block until the subprocess terminates.
Frankly at this point the best I can think of is just using a batch file (though that would have to be OS-specific as far as I know)?
So I wonder if anyone knows whether want I want to do is possible?
Thanks!
Brian

Running Mac application in same thread as parent script

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?

pexpect output in different window

Now I am working in a project where the testscript has to connect many (3-10) remote computers (SSH and do some stuff).
I started to use the pexpect and it is simple as a button. It works fine.
I want to see the communication during test. I know it is possible to redirect the log to the screen. But in this case the logs (from different computer) are mixed.
What I would like is to open new terminal window (or consol or whatever) for every new spawn object. In this case I could see all communication in different windows. Additionally I would like to keep the possibility of spawn.interact() in every window.
I feel that it is possible somehow but I don't know how. I think some file pointer (or pipe) should pass to the new window somehow(?)
(SecureCRT knows sometihng like this, it has tabbed consol windows and can access them separately, but it is a commercial product)
Or let me make the problem more simple.
If I do this, I can open a new shell in a new window:
p=Popen(["cygstart", "bash"])
How can I read and write into this shell from my script (parent) to see it in this new window?
I would really appreciate it, if one of you could point me in the right direction.
It is enough if you tell me what to read or find for (on Google) because I did not find anybody such kind of problem.
The environment is cygwin.
Thanks in advance
br:drv
Have you tried using the logfile parameter?
child = pexpect.spawn('some_command')
mylog = open('/tmp/mylog','w')
child.logfile = mylog
This will automatically log all communication to the file, including commands you enter after calling spawn.interact()
More info available on the website: http://pexpect.sourceforge.net/pexpect.html
Search for 'logfile' to find the relevant documentation.

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