Python and platforms
July 30, 2018 at 1:26 PM by Dr. Drang
After my last post on the scripts that generate my Apple sales graphs (which I’ll need again when the new quarterly results are posted tomorrow), I was shamed by Rosemary Orchard and Nathan Grigg into rewriting them to run on both macOS and iOS (the latter via Pythonista). It turned out to be pretty easy, with only a couple of additions needed.
I won’t bore you with the entire script, I’ll just bore you with the new stuff that lets the script run on both platforms. There were two changes.
First, since there is no OptiPNG for iOS, this line in the original script,
python:
subprocess.run(['optipng', pngFile])
which processed the just-saved file on my Mac, had to go. The fix, though, wasn’t too much different: just run OptiPNG on the server after the file was uploaded. I already had an SSH connection to the server, so all I had to do was add this line,
python:
sshIn, sshOut, sshErr = ssh.exec_command("optipng '{}'".format(pngDest))
before closing the connection. The exec_command
function is part of the paramiko
SSH library, and pngDest
is a variable that contains the full path on the server to the newly uploaded PNG file.
The second change was really more of an addition than a change. I decided I wanted the script to put the uploaded PNG’s URL on the clipboard to make it easy to paste into a blog post. This is easy to do on the Mac, where you just use subprocess
to run the pbcopy
command;1 and it’s even easier to do on iOS, where Pythonista includes the handy clipboard
library. The problem comes in figuring out which device the script is running on.
(It’s possible this problem has already been solved and is sitting in GitHub repository, but I didn’t find it. Al Sweigart’s pyperclip
is a cross-platform library for moving text to and from the clipboard, but the platforms it crosses are the traditional Windows, Mac, and Linux—no iOS.)
At first, I thought calling os.name
would give me what I needed, but it returns posix
on both macOS and iOS. After a bit of searching, I hit upon the platform
library, which I’d never used before. In particular, the platform.platform()
function returns the string
Darwin-17.6.0-x86_64-i386-64bit
on my 2012 iMac at home,
Darwin-17.7.0-x86_64-i386-64bit
on my 2017 iMac at work,
Darwin-17.7.0-iPad6,3-64bit
on my iPad Pro, and
Darwin-17.7.0-iPhone8,1-63bit
on my iPhone 6s. I don’t understand why the minor Darwin number is one less on the home iMac than it is everywhere else, but it doesn’t matter for what I need here. The key is that Macs have “x86” in the string (at least for now) and it’s a safe bet that iOS devices never will.
Thus, the following section of code at the end of my script:
python:
if 'x86' in platform.platform():
import subprocess
subprocess.Popen('pbcopy', stdin=subprocess.PIPE).communicate(pngURL.encode())
else:
import clipboard
clipboard.set(pngURL)
As its name implies, pngURL
is a string that contains the URL of the just-uploaded and optimized PNG file. Applying encode
to it before sending it to communicate
is necessary because communicate
takes only bytes
.
Oh, there is one more thing. I used to keep the Apple sales scripts and data files in a Dropbox folder, but now I have them in a folder on iCloud Drive. Pythonista’s external files feature can link to individual Dropbox files, but I couldn’t get it to link to a folder, and I kept getting errors whenever a script on Dropbox tried to save a file. Both of these problems disappeared when I moved everything to iCloud.2
So thanks to Rosemary and Nathan for the nudge. I didn’t think I wanted an iOS-resident solution, but now that I have it, it seems pretty neat.
-
That link should go to Apple’s online man page for the
pbcopy
command, but Apple has decided either to delete its man pages or move them where neither I nor Google can find them. Have I complained about this before? Yes, and I’m complaining about it again. ↩ -
I’ve been thinking about switching entirely from Dropbox to iCloud, but that’s a topic for another post. ↩