Saturday
Feb142015

Saving email attachments with pre-pended YYYY-MM-DD_

Multiple times a week I receive an email with attached report files that I need to save for one reason or another. I save these to a few different folders, depending on type of report. The filenames of these attachments are often unchanged from the last N times I received this type of report. So, I like to prepend the date in the form "YYYY-MM-DD_..." to the filename.

(As an aside: I do not trust email attachments for longer-term archival storage. I've had too many attachments, as in a dozen or more, be corrupted months or years later when I tried to re-access them.)

This is an easy task that is ripe for automation.


Everything above this line is True. Everything below, well, let's just say it worked when I wrote the draft of the post, and stopped working moments after I clicked Publish. See this next post for an updated version that actually works

Edited to add: If you are running 10.10 Yosemite (or maybe 10.9), this may not work reliably. See this thread about issues with AppleScript access to Mail.app attachments. So, good luck & no guarantees...


Below is an AppleScript that does this to the attachments of the selected email message. There are many ways to trigger this AppleScript, but in my case I've created a simple workflow in Alfred.

The only thing I haven't figured out is why Default Folder X isn't active in my Alfred-triggered AppleScript. It was when I ran it from Script Editor. Weird.

And, here's the AppleScript:

Friday
Oct312014

Controlling a powerUSB power strip from python on Mac OS X

I needed to inexpensively control some electronics hardware in my office. I found that powerUSB sells a reasonably priced USB controlled power strip with three controllable AC ports. (A fourth port is always on.)

From their website you can download a Mac software package that includes a GUI app (works fine, but not useful for anything scripted) and a command line tool (works fine for controlling, but I could never figure out how to get it to read outlet states back to me). If the command line utility had worked better I probably would have been fine with calling it from python. So, to fix that I wrote a package to control the powerUSB outlets from python.

The github repository is here.

The PyPI package is here.

You will need to have swig tools installed. (If you're using Enthought's Canopy you can install swig from their package manager.)

You will also need to have some version of libusb-1.0 installed. No doubt one could easily modify the pwrusb package to work against other USB libraries, but I chose libusb-1.0 because it is so easily installed from homebrew with brew install libusb.

Installing the pwrusb package is super easy from PyPI:

pip install pwrusb

Note that to avoid any possible copyright issues, I did not include any of the powerUSB code in the distribution. Instead, the necessary code and library will be downloaded from their website downloads section automatically during build & install. Only problem will be when they inevitably change the paths on their website.

You address a single outlet at a time, e.g.:

In [1]: import pwrusb

In [2]: bank = 0

In [3]: for outlet in [1, 2, 3]:
   ...:     print "outlet {} is {}".format(outlet, pwrusb.get_single_outlet_state(bank, outlet))
   ...:     
outlet 1 is 0
outlet 2 is 0
outlet 3 is 0

In [4]: pwrusb.set_single_outlet_state(bank, 2, True)

In [5]: for outlet in [1, 2, 3]:
    print "outlet {} is {}".format(outlet, pwrusb.get_single_outlet_state(bank, outlet))
   ...:     
outlet 1 is 0
outlet 2 is 1
outlet 3 is 0

In [6]: pwrusb.set_single_outlet_state(bank, 2, False)

In [7]: for outlet in [1, 2, 3]:
    print "outlet {} is {}".format(outlet, pwrusb.get_single_outlet_state(bank, outlet))
   ...:     
outlet 1 is 0
outlet 2 is 0
outlet 3 is 0
Thursday
Oct022014

Head, meet wall - Do not use a mutable as a default parameter in python

Remember that default parameters in python are evaluated at the time of definition.

I knew this, I really did. Can it be Friday yet?

In the following for the BadIdea class a single list is created and every instance of BadIdea is referencing that same list. Far better to make the default None, test for that, and set to an empty list as necessary.

Monday
Aug252014

Demo of launching a traitsui GUI as a separate process and then communicating with it via STDIN/STDOUT

Without going into the details of why, I want to be able to launch a traitsui gui from a python command line and communicate back-and-forth with it while maintaining use of the command line. I played with implementing this with threads in a couple of ways, but those were unsatisfactory as the command line would sometimes go unresponsive for seconds at a time.

Then I had the realization to just launch the traitsui GUI as a separate process and communicate with it via stdin and stdout. So, here's a demo that implements just a few commands and the simplest possible GUI, just a status field in a window. The full code is below.

The only real trick was to include a thread watching for the PID of the original python session to disappear. Otherwise the GUI is left hanging there when the python session is exited.

As an example session in python:

In [1]: from talk2subprocess_traitsui import talker
In [2]: t = talker()  # gui launches
In [3]: t.send_yes()  # gui status window shows the 'yes' message was received
In [4]: t.send_question()  # the question is answered and we get it returned to us
the answer is 83
Out[4]: 83
In [5]: t.shutdown()  # gui closes as intended
In [6]: t = talker()  # gui re-launches
In [7]: quit   # a few seconds later gui disposes of itself

Here's the demo:

Tuesday
Aug192014

Demo of Enthought's TraitsUI with matplotlib and a popup menu

I've been using Enthought's traits and traitsui to build a couple of GUI tools that display images and plots with matplotlib.

While there's a nice tutorial on using matplotlib within traitsui written by Gael Varoquaux, it was a bit more work to make a right click popup menu work on top of a matplotlib figure.

Here it is, just in case someone (perhaps me) is searching for such an example in the future: