Home | Flickr Photos | Links | About | Resume | Contact Me

Lesson Learned: Don’t Monkey Patch

Well this post comes as a lesson learned the hard way and a warning to fellow programmers in dynamic languages. In a sentence, don’t monkey-patch. Seriously, just don’t do it.

With the advent of dynamic languages like Python we are treated with very powerful yet dangerous features. Monkey patching, the practice of substituting one unit of functionality with another at runtime is one of those really dangerous things.

It started out simply enough, I wanted some functionality from the standard cgi library in python; so I copied the relevant functions into my code and went about my merry way with everything working well. This felt a little dirty at the time since it violates DRY and I really try to keep my code DRY. Well I tend to write my code first and rough in the documentation then give everything a once-over and touch up documentation and unit tests before I commit it for production use. This is where I tend to get myself in trouble.

Lo and behold, I’m going back over this set of code and realize that I really don’t need to copy and paste the code but rather I can just replace one function in the standard library with my customized version. So I did and so began my troubles.

So it bears stepping back and really understanding what was happening here. In Python the real act of importing a module happens only once for the entire life of your program. When the compiler is asked to import a module it will parse it once and after that all you’re doing is importing it into your namespace, its already parsed and any module-level variables remain the same for the entire duration of your program. So, lets say for example you import the cgi module in a class deep within your program and decide to monkey-patch it. But, unbeknown to you the application server with which you share a namespace also imports this cgi module and uses it to handle the script environment. Well now everything works just great until your monkey-patch gets executed, then all of a sudden the remainder of your script will use the modified cgi module.

Lets also consider that your application server runs in two modes, for the sake of example; a fastcgi mode where application server processes can linger for hours and a cgi mode where application servers are spawned and killed with each request. Now you’ve got a seriously sneaky bug on your hands. Your code is going to potentially fail in one environment and run just fine in the other. Oh and now, no matter how much you look at that code you’re not going to understand why it’s failing until you realize what you’ve done by monkey-patching something.

This is the story of my day. A hard learned lesson. However, much thanks to my patient co-workers who helped me to see the error of my ways. Head this warning and do not monkey-patch things, your co-workers may not be so kind :-).

Fine print: Ok, so I know there are some legitimate cases for monkey-patching, however I’m learning that those are pretty rare and in general its a dangerous practice in which to engage.

Perl from Python? Intriguing yet gross.

So I’m probably late to the party on this one but apparently you can import perl from within python. Now, why you would want to do this kind of baffles me, however, it is really pretty interesting and could have some possibilities if you’re maintaining a legacy perl application that you’re porting to python. If nothing else its an interesting academic exercise.

Mac Terminal Keys

One of the most annoying things with Apple’s Terminal.app is that the key bindings for paging an home/end are all kinds of screwed up. I’ve actually had these on my MBP for a while but was setting up a new Mac today and figured I’d throw them out here for the benefit of the rest of the web.

To restore keyboard settings that make sense to users coming from other terminals you’ll need to edit the “Keyboard” settings of your favorite theme. These are the correct settings, they all require setting “Action” to “send string to shell”; use the escape key to enter \033:

Key Action
home \033[H
end \033[F
page up \033[5~
page down \033[6~

iPython Readline on Leopard

iPython is a really great tool for working with Python interactively but its less than awesome on Leopard. Why you might ask? Well, included in the list of sins Apple has comitted with Leopard’s terminal environment was shipping a broken version of readline. The good news is it’s easy to fix! The iPython folks have a version of readline that works on Leopard. Just easy_install it and rock out with full readline support, including working home and end keys.

sudo easy_install -f http://ipython.scipy.org/dist readline

Custom Terminal Colors on Leopard

The Apple terminal is arguably one of the places I spend the most time on my mac, but the program is quite lacking. Apple did a good job improving it in Leopard but they just didn’t quite fix everything that was broken.

Among its issues is the fact that there is no built-in way to handle changing the default colors. This probably makes sense if you’re looking at a white terminal with colored text on it. However if you’re like me and find black or very dark backgrounds less abusive to your eyes you’ve no doubt found some of the colors utterly miserable to read, especially blues.

Well after find out that a co-worker was having similar issues I did some digging and found an absolutely amazing SIMBL plugin by Ciaran Walsh (of TextMate plugin fame) that fixes that. Check it out at his site. It’s probably one of the more useful plugins I have.

Screenshots and notes after the jump.

Continue reading ‘Custom Terminal Colors on Leopard’

Base36 in Python

Today I had to deal with some base36 encoded data in Python. Well my first instinct was “my_data”.decode(”base36″) which was a no-go. Next up, poke about in the base64 module since it also does base32 and base16; this netted me similar results. Asking Google got me some results but nothing I liked. It seems that people like to use static strings as lookup tables for the encoding which bothered me. I’m not sure why it bothered me, but it did. Anyhow, so I rolled my own this evening that I plan to use tomorrow. I offer it up to the world as (in my not so humble opinion) a superior choice to the other base36 implementations out there.

Check it out at: http://mike.crute.org/svn/projects/misc_modules/base36.py

If you find it useful or find a bug let me know. I probably won’t be doing much more with it other than bug fixes if there are any.

Coolest CMS Commercial Ever?

I was reading through the backlog of stuff in Google Reader today and came across a Vitamin article by Drew Wilson about creating a better CMS and while I generally agree with his points the thing that most intrigued me was the mention of the ad he created for is product Firerift. While I can’t say too much about the product as I haven’t tried it out yet the commercial is really pretty sweet (at least for a CMS). Actually come to think of it I don’t think I’ve ever seen a commercial for a CMS before.

Oh yeah, and the fact that he used music from Underoath is pretty darn cool too. The song is “Casting Such a Thin Shadow” if anybody was curious.

Making Nosetests w/Coverage Awesome

So I’ve become test infected, nosetests is a great testing framework and with the coverage plugin it’ll even tell me how good (or generally bad) I am at testing all of my code. Coverage does have one major problem, it’s really finicky about how you call it and its really dumb when it comes to auto-detecting what you want it to do.

Well being a lazy person (I’m a programmer after all) I figured I’d write a quick shell function for my .bashrc file to make coverage not suck; and so I humbly deliver to you, teh intarwebs, the following:

function nosecover {     local basepath="${SB}/src/applib/"     if [[ `pwd` != ${basepath}* ]]; then         echo "You don’t want to run this outside your sandbox."         return 1     fi           # sed pretty much hates it if you don‘t escape your slashes     local cb=`echo ${basepath} | sed -e ‘s/\\//\\\\\//g‘`     local loc=`pwd | sed -e "s/$cb//g" -e "s/\\//./g" -e "s/\\.tests//g"`     local tf="./"         # If $1 has test_*.py then use that as our nose path     if [[ $1 == *test_*.py ]]; then         tf=$1         # If $2 has test_*.py then use that as our nose path     # and assume $1 is our cover package     elif [[ $2 == *test_*.py ]]; then         tf=$2         loc=$1     fi       # Always remember to pick your nose before use     find . \( -name ‘*.pyc‘ -o -name ‘.coverage\) -exec rm ‘{}\;             echo "nosetests –with-coverage –cover-erase –cover-package=$loc $tf"     nosetests –with-coverage –cover-erase –cover-package=$loc $tf }

In a nutshell if you just run nosecover and you’re in the directory of the package for which you’d like to get coverage info this function will figure out what your cover-package is and run nose for you. Optionally you may pass a single argument of the specific test to run, or you may pass both a cover package and a test file (in that order) to just skip typing the nose command. This will also clean out any *.pyc and .coverage files so you get accurate results from nose. That’s about it, nothing revolutionary, just a nice shortcut.

Now, for the keen observer, you’ll note that there are some AGI specific things in here that you’ll need to customize for your environment. You’ll need to change basepath to wherever your Python code lives but that should be about it.

Go forth and suck less!

Python Apache Library (plus htaccess)

I’ve been working on switching over a bunch of my Apache web servers to run lighttpd and ran into a small problem with authentication. Lighttpd supports Apache style htpasswd files for authentication, but the catch is that it doesn’t come with any tool to manipulate them like Apache does. They do offer a Perl script on their site that will do basic htpasswd file manipulation but I’m no big fan of Perl and I’m always up for a challenge. So I set forth to write a Python clone of the htpasswd tool.

About half-way through writing my new htpasswd tool I got the bright idea to break out the functionality into a library called apachelib. Since I was striving for a feature-complete htpasswd clone I wanted to be sure to implement every function. Well, that’s fine and easy until I got to the MD5 hashing. Apache takes a, shall we say, “unique” approach to generating its MD5 hashes. Well after some quality time with the APR C code I’ve duplicated Apache’s MD5 hashing routine in Python. Check it out in my subversion repository. I’m still working on the front-end to htpasswd but all the back-end code is in there and complete. Just import apachelib.htpasswd or apachelib.md5.

I’m also considering writing a class wrapper for htpasswd files so that they can be easily manipulated in Python. I’ll probably do that at some time and incorporate it into apachelib. I can imagine how it would be useful to integrate a real user-manager into Trac, since it relies on the web server for authentication and the web server relies on htpasswd files. Anyhow, more on that later when it materializes.

Subversion Repo

I’ve just started up my own personal subversion repository for any of the various (non-classified ;-)) projects that I’m working on. Everything in there will be open source of some sort and as time goes on I’ll be sorting through some older code that I’ve written to see if there is anything useful worth checking in. For now the only thing I’ve put in there is my pybind stuff. You can find the repository at http://mike.crute.org/svn

DISCLAIMER: The opinions expressed on this website are mine and mine alone, they should not be interpreted as the views of my employers, past or present, my family, my church or my pets. Comments are the property of their posters and I can not be held accountable for those.