When is a bool not a bool?

When is a bool not a bool? In Python, of course.

You see, once upon a time (specifically the late 80s and early 90s), some guy named Guido started implementing a new programming language. One that would be pragmatic, uncluttered, and compact, yet highly opinionated. It’s a neat language, but not without its drawbacks.

Most of my day-to-day work is done in Python. Just yesterday I discovered a most interesting quirk of the language. Because Python is a duck-typed language, values of one type can be frequently interpreted as values of another type. In fact, some of this is by design. In the Python “days of old”, there wasn’t even a bool type – just int values of 0 or 1.

What I was working with in my codebase was a bit of logic to read an optional config value, check if it was an int (intending for None or False as a value to mean that the config flag was disabled) and if so, act accordingly with that int1.

Anyway, here’s an approximation of the code used:

def scrambled_subset(query, config):
    if isinstance(config.QUERY_LIMIT, int):
        query = query.order_by(fn.RANDOM).limit(config.QUERY_LIMIT)

    # ...
    # More implementation
    # ...
    
    return query

There was more going on overall here, but that’s the gist of it. The intended effect? If there was a limit configured, limit the query to that many rows. The limit was in play for some time, but then the need came to remove the limit – so I set config.QUERY_LIMIT to False, thinking “welp, False definitely is not an int2.

So, there I was watching the consumer of that (so I thought) un-limited query have no rows to act on. What the what? So I did some poking around the code.

>>> type(False)
<type 'bool'>
>>> isinstance(False, bool)
True
>>> isinstance(False, int))
True 

Um.

So after a little bit more research, I found that Python’s bools are totally acceptable ints. They even have prescribed values:

>>> False + 1
1
>>> True + 1
1
>>> 2 ** (True + 1)
4
>>> 2 ** (- True)
0.5
>>> 2 ** False
1
>>> False ** 2
0

So there you have it, folks. In Python, a bool is really just a fancy fucking int.

  1. Interestingly, this bug should have shown itself from day one, but because the code inside the conditional block had its own issue (in particular, an ORM whose LIMIT clause for queries was broken when the query was “sorted” by RANDOM…) it remained hidden until the dependency’s bug was actually fixed. 

  2. In hindsight, I probably should have set to None – I think an initial version of this expected the config value to be a flag and the limit quantity was hardcoded to some value. The config just enabling or disabling the hardcoded limit. 

Swizzling in Python

Story Time

Ever come across a Python library with some kind of shortcoming that you know you can fix, but don’t want to fork, fix, pull-request, wait five weeks, then update in order to get moving? Are you even too lazy to do just the first two steps and point your dependency manager at your own fork? Don’t worry, you can probably fix it in code.

Right now I’m writing a Slack bot library that will support, in addition to the commonplace single command/response paradigm, a more conversational paradigm for multi-step commands and workflows. So, like a good programmer, I set up my module structure, my setup.py, and got moving. This was after a little bit of proof-of-concept code sketching, in which I came up with the general flow of connecting with the official Slack client for python, aptly named python-slackclient. So, I ported the flow into my library’s code, with some nicer structure, fired up a virtualenv, ran python setup.py develop, and then wrote a little wrapper script to invoke the client.

Boom, error. Weird, right? My proof-of-concept had worked fine…

After looking at Slack’s code, I found that it was cleansing an exception from the websocket-client library, where it was having problems locating my system’s Root Certificate Authority file. That’s a problem I don’t really want to deal with right now. I have a feeling it has to do with the path magic that python setup.py develop does, so I’m willing to let it go. Nonetheless, I’m still stuck with it not working, and no way to tell the Slack client to get its head out of its ass and find the Root CA file for the websocket client.

Or is there?

Investigation

The websocket-client method, create_connection takes a URL by default but also takes some kwargs, one of which is sslopt, a dictionary of values describing SSL options, including the location of the Root CA file. Additionally, the ssl standard library includes methods for retrieving the location of said file. But, again, the calling of create_connection is within the Slack client’s code! What do I do?

Swizzle that shit!

Swizzling, for the uninitiated, is the same thing as monkey-patching, which is to say, replacing at runtime the implementation of a method on a class. Alas, it’s a little more complex in this case, since the method I want to swizzle is on the class of an object, an instance of which is held by the Slack client. So, I ended up using a subclass of the client and overloading the initializer to dig into the client’s state and swizzle the method in question.

Check it out!

Note that you have to bind the newly-defined method to the class, meaning that if you only have a reference to an instance, you need to use the __class__ attribute to get the class itself. Don’t forget self as the first argument; this is important for the method to bind correctly to the class/instance.

Oh, so, by the way, that Slack bot library I’m working on can be found here: SlackBorg.

Please

I wrote this the other day on a dare from a friend of mine. It only works in Bash (and I use ZSH) but I think it’s funny anyway.

Just:

  • Make sure you have bash-preexec installed
  • Put .please.py in your home directory
  • Put the contents of the Gist’s .bashrc in your .bashrc

OS X Notifications from the Shell

I have one big productivity suck when working: asynchronous tasks.

Just like in code, I think it’s in pretty poor taste (not to mention inefficient) to start something and then just keep checking on it until you see it’s done. Not only that, but it’s easy to forget to check.

This is what happens to me when dealing with my unit and integration tests. Maybe I’ll go read an article while they’re running or even drop into Reddit (which is a mistake in all cases), or if I’m a good boy I’ll go update some documentation and style somewhere around my codebase that needs it.

In code, we’ve solved this problem with callbacks. Make an HTTP call and just tell it to let you know when the response comes back, instead of blocking everything else or continuously checking some value somewhere until it’s changed to complete. It kind of dawned on me that I have a $3,000 callback machine in front of me; why not make it work for me? I get a notification when someone posts on my Facebook wall, when I’m tweeted at, and when my Amazon purchase ships – why not get one when my tests are complete?

I’m not a big IDE fan, and I’m sure IDEs do this (I mean, Xcode does, of course) but when working in Python I like to work primarily in the command line when it comes to testing and execution. I did some research, and found that Apple exposes some Notification Center functionality to AppleScript, and I know that I can execute arbitrary AppleScript via the osascript command, so, voilà, I can post notifications from the shell.

All that was left is putting in some logic to display different messages based on parameters and whether or not the tests succeeded. Check out the gist below for a basic version of what I ended up implementing (my real version has some proprietary stuff in it, so I had to write a simpler version for demo purposes!).

I’d love some feedback, so please let me know what y’all think!

tmux 2.1 and mode-mouse

I’ve been having an issue the last couple days that I couldn’t figure out. I had upgraded most tools on my machine as I tend to do every once in a while, and after a few days I noticed that my mouse integration in tmux wasn’t working quite the way I expected. Turns out, they had made a significant change to the mousing mode without documenting it very well, or at least without anything past putting in the changelog. I guess I should have read it, but the software should probably tell the user that a feature they’re trying to use has been replaced.

At any rate, here’s the config I had before, more or less:

After the update to tmux 2.1, I found that I needed only this:

It’s actually a lot more convenient, but it was frustrating that I had to search so far to find the solution. I’m by no means a tmux expert so if there’s anything about this or other parts of my config that seem wrong or distasteful, I’d love to hear about it.