<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Musings of an Anonymous Geek</title>
	
	<link>http://www.protocolostomy.com</link>
	<description>Made with only the finest 1's and 0's</description>
	<lastBuildDate>Mon, 19 Jul 2010 12:31:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/MusingsOfAnAnonymousGeek" /><feedburner:info uri="musingsofananonymousgeek" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>MusingsOfAnAnonymousGeek</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2FMusingsOfAnAnonymousGeek" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FMusingsOfAnAnonymousGeek" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/MusingsOfAnAnonymousGeek" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FMusingsOfAnAnonymousGeek" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FMusingsOfAnAnonymousGeek" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FMusingsOfAnAnonymousGeek" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><item>
		<title>Wonky Bunny Issue “Fixed”</title>
		<link>http://feedproxy.google.com/~r/MusingsOfAnAnonymousGeek/~3/W8OwfFuOXR0/</link>
		<comments>http://www.protocolostomy.com/2010/07/19/wonky-bunny-issue-fixed/#comments</comments>
		<pubDate>Mon, 19 Jul 2010 12:31:02 +0000</pubDate>
		<dc:creator>m0j0</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=819</guid>
		<description><![CDATA[For those who don&#8217;t know what the headline means: Bunny is an open source command line utility written in Python that provides a shell for talking to and testing AMQP brokers (tested on RabbitMQ). AMQP is a queuing protocol. It&#8217;s defined as a binary wire-level protocol as well as a command set. The spec also [...]]]></description>
			<content:encoded><![CDATA[<p>For those who don&#8217;t know what the headline means:</p>
<ol>
<li><a href="http://github.com/bkjones/bunny/">Bunny</a> is an open source command line utility written in Python that provides a shell for talking to and testing AMQP brokers (tested on RabbitMQ).</li>
<li>AMQP is a queuing protocol. It&#8217;s defined as a binary wire-level protocol as well as a command set. The spec also defines a good portion of the server semantics, so by that logic Bunny should work against other AMQP brokers besides RabbitMQ</li>
<li>RabbitMQ is written in Erlang atop OTP, so clustering is &#8216;free and easy&#8217;. My experience with RabbitMQ so far has been fantastic, though I&#8217;d like to see client libraries in general mature a bit further.</li>
</ol>
<p>So, Bunny had this really odd quirk upon its first release. If you did something to cause an error that resulted in a connection being dropped, bunny wouldn&#8217;t trap the error. It would patiently wait for you to enter the next command, and fail miserably. The kicker is that I actually defined a &#8216;check_conn&#8217; method to make sure that the connection was alive before doing anything else, and that really wasn&#8217;t working.</p>
<p>The reason is because py-amqplib (or, perhaps, its interpretation of the AMQP spec, which defines a Connection class), implements a high-level Connection class, along with a Channel class (also defined in the spec), which is what seems to actually map to what you and I as users actually care about: some &#8220;thing&#8221; that lets us communicate with the server, and without which we can&#8217;t talk to the server.</p>
<p>With py-amqplib, a Connection is actually defined as a channel 0, and always channel 0. I gather that channel 0 gets some special treatment in other sections of the library code, and the object that lives at index &#8217;0&#8242; in Connection.channels is actually defined as a Connection object, whereas others are Channel objects.</p>
<p>The result of all of this is that creating a channel in my code and then checking my own object&#8217;s &#8216;chan&#8217; attribute is useless because channels can be dropped on the floor in py-amqplib, and the only way I can tell to figure that out is to check the connection object&#8217;s &#8216;channels&#8217; dictionary. So that&#8217;s what I do now. It seems to be working well.</p>
<p>Not only does bunny now figure out that your connection is gone, but it&#8217;ll also attempt a reconnect using the credentials you gave it in the last &#8216;connect&#8217; command. You see, bunny extends the Python built-in cmd.Cmd object, which lets me define my whole program as a single class. That means that whatever you type in, like the credentials to the &#8216;connect&#8217; command, can be kept handy, since the lifetime of the instance of this class is the same as the lifetime of a bunny session.</p>
<p>So, in summary, bunny is more useful now, but it&#8217;s still not &#8220;done&#8221;. I made this fix over the weekend during an hour I unexpectedly found for myself. It&#8217;s &#8220;a&#8221; solution, but it&#8217;s not &#8220;the&#8221; solution. The real solution is to map out all of the errors that actually cause a connection to drop and give the user a bit more feedback about what happened. I also want to add more features (like support for getting some stats back from Alice to replace bunny&#8217;s really weak &#8216;qlist&#8217; command).</p>
<script type="text/javascript">
  addthis_url    = 'http%3A%2F%2Fwww.protocolostomy.com%2F2010%2F07%2F19%2Fwonky-bunny-issue-fixed%2F';
  addthis_title  = 'Wonky+Bunny+Issue+%26%238220%3BFixed%26%238221%3B';
  addthis_pub    = 'jonesy';
</script><script type="text/javascript" src="http://s7.addthis.com/js/addthis_widget.php?v=12" ></script>

<p><a href="http://feedads.g.doubleclick.net/~a/TmI0mFfmikf0tfCflsXuNFAoTJk/0/da"><img src="http://feedads.g.doubleclick.net/~a/TmI0mFfmikf0tfCflsXuNFAoTJk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/TmI0mFfmikf0tfCflsXuNFAoTJk/1/da"><img src="http://feedads.g.doubleclick.net/~a/TmI0mFfmikf0tfCflsXuNFAoTJk/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=W8OwfFuOXR0:mk7XDchu3pc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=W8OwfFuOXR0:mk7XDchu3pc:bcOpcFrp8Mo"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=bcOpcFrp8Mo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=W8OwfFuOXR0:mk7XDchu3pc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?i=W8OwfFuOXR0:mk7XDchu3pc:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/MusingsOfAnAnonymousGeek/~4/W8OwfFuOXR0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2010/07/19/wonky-bunny-issue-fixed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.protocolostomy.com/2010/07/19/wonky-bunny-issue-fixed/</feedburner:origLink></item>
		<item>
		<title>Python Date Manipulation</title>
		<link>http://feedproxy.google.com/~r/MusingsOfAnAnonymousGeek/~3/jUFOBc-XfdI/</link>
		<comments>http://www.protocolostomy.com/2010/07/06/python-date-manipulation/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 14:56:33 +0000</pubDate>
		<dc:creator>m0j0</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=781</guid>
		<description><![CDATA[This post is the result of some head-scratching and note taking I did for a reporting project I undertook recently. It&#8217;s not a complete rundown of Python date manipulation, but hopefully the post (and hopefully the comments) will help you and maybe me too The head-scratching is related to the fact that there are several [...]]]></description>
			<content:encoded><![CDATA[<p>This post is the result of some head-scratching and note taking I did for a reporting project I undertook recently. It&#8217;s not a complete rundown of Python date manipulation, but hopefully the post (and hopefully the comments) will help you and maybe me too <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>The head-scratching is related to the fact that there are several different time-related objects, spread out over a few different time-related modules in Python, and I have found myself in plenty of instances where I needed to mix and match various methods and objects from different modules to get what I needed (which I thought was pretty simple at first glance). Here are a few nits to get started with:</p>
<ul>
<li>strftime/strptime can generate the &#8220;day of week&#8221; where Sunday  is 0, but there&#8217;s no way to tell any of the conversion functions like  gmtime() that you want your week to start on Sunday as far as I know.  I&#8217;m happy to be wrong, so leave comments if I am. It seems odd that you  can do a sort of conversion like this when you output, but not within  the calculation logic.</li>
<li>If you have a struct_time object in localtime format and want to convert  it to an epoch date, time.mktime() works, but if your struct_time  object is in UTC format, you have to use calendar.timegm() &#8212; this is  lame and needs to go away. Just add timegm() to the time module  (possibly renamed?).</li>
<li>time.ctime() will convert an epoch date into nicely formatted local  time, but there&#8217;s no function to provide the equivalent output for UTC  time.</li>
</ul>
<p>There are too many methods and modules for dealing with date  manipulation in Python, such that performing fairly common tasks  requires importing and using a few different modules, different object  types and methods from each. I&#8217;d love this to be cleaned up. I&#8217;d love it  more if I were qualified to do it. More learning probably needs to  happen for that. Anyway, just my $.02.</p>
<h3>Mission 1: Calculating Week Start/End Dates Where Week Starts on Sunday</h3>
<p>My mission: Pull epoch dates from a database. They were generated on a machine whose time does not use UTC, but rather local time (GMT-4).  Given the epoch date, find the start and end of the <em>previous</em> week, where the first day of the week is Sunday, and the last day of the week is Saturday.</p>
<p>So, I need to be able to get a week start/end range, from Sunday at 00:00 through Saturday at 23:59:59. My initial plan of attack was to calculate midnight of the current day, and then base my calculations for Sunday 00:00 on that, using simple timedelta(days=x) manipulations. Then I could do something like calculate the next Sunday and subtract a second to get Saturday at 23:59:59.</p>
<h4>Nothing but &#8216;time&#8217;</h4>
<p>In this iteration, I&#8217;ll try to accomplish my mission using only the &#8216;time&#8217; module and some epoch math.</p>
<p>Seems like you should be able to easily get the epoch value for midnight of the current epoch date, and display it easily with time.ctime(). This isn&#8217;t quite true, however. See here:</p>
<pre>&gt;&gt;&gt; etime = int(time.time())
&gt;&gt;&gt; time.ctime(etime)
'Thu May 20 15:26:40 2010'
&gt;&gt;&gt; etime_midnight = etime - (etime % 86400)
&gt;&gt;&gt; time.ctime(etime_midnight)
'Wed May 19 20:00:00 2010'
&gt;&gt;&gt;
</pre>
<p>The reason this doesn&#8217;t do what you might expect is that time.ctime() in this case outputs the local time, which in this case is UTC-4 (I live near NY, USA, and we&#8217;re currently in DST. The timezone is EDT now, and EST in winter). So when you do math on the raw epoch timestamp (etime), you&#8217;re working with a bare integer that has no idea about time zones. Therefore, you have to account for that. Let&#8217;s try again:</p>
<pre>&gt;&gt;&gt; etime = int(time.time())
&gt;&gt;&gt; etime
1274384049
&gt;&gt;&gt; etime_midnight = (etime - (etime % 86400)) + time.altzone
&gt;&gt;&gt; time.ctime(etime_midnight)
'Thu May 20 00:00:00 2010'
&gt;&gt;&gt;
</pre>
<p>So, why is this necessary? It might be clearer if we throw in a call to gmtime() and also make the math bits more transparent:</p>
<pre>&gt;&gt;&gt; etime
1274384049
&gt;&gt;&gt; time.ctime(etime)
'Thu May 20 15:34:09 2010'
&gt;&gt;&gt; etime % 86400
70449
&gt;&gt;&gt; (etime % 86400) / 3600
19
&gt;&gt;&gt; time.gmtime(etime)
time.struct_time(tm_year=2010, tm_mon=5, tm_mday=20, tm_hour=19, tm_min=34, tm_sec=9, tm_wday=3, tm_yday=140, tm_isdst=0)
&gt;&gt;&gt; midnight = etime - (etime % 86400)
&gt;&gt;&gt; time.gmtime(midnight)
time.struct_time(tm_year=2010, tm_mon=5, tm_mday=20, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=140, tm_isdst=0)
&gt;&gt;&gt; time.ctime(midnight)
'Wed May 19 20:00:00 2010'
&gt;&gt;&gt; time.altzone
14400
&gt;&gt;&gt; time.altzone / 3600
4
&gt;&gt;&gt; midnight = (etime - (etime % 86400)) + time.altzone
&gt;&gt;&gt; time.gmtime(midnight)
time.struct_time(tm_year=2010, tm_mon=5, tm_mday=20, tm_hour=4, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=140, tm_isdst=0)
&gt;&gt;&gt; time.ctime(midnight)
'Thu May 20 00:00:00 2010'
&gt;&gt;&gt;
</pre>
<p>What&#8217;s that now? You want what? You want the epoch timestamp for the previous Sunday at midnight? Well, let&#8217;s see. The time module in Python doesn&#8217;t do deltas per se. You can calculate things out using the epoch bits and some math if you wish. The only bit that&#8217;s really missing is the day of the week our current epoch timestamp lives on.</p>
<pre>&gt;&gt;&gt; time.ctime(midnight)
'Thu May 20 00:00:00 2010'
&gt;&gt;&gt; struct_midnight = time.localtime(midnight)
&gt;&gt;&gt; struct_midnight
time.struct_time(tm_year=2010, tm_mon=5, tm_mday=20, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=140, tm_isdst=1)
&gt;&gt;&gt; dow = struct_midnight.tm_wday
&gt;&gt;&gt; dow
3
&gt;&gt;&gt; midnight_sunday = midnight - ((dow + 1) * 86400)
&gt;&gt;&gt; time.ctime(midnight_sunday)
'Sun May 16 00:00:00 2010'
</pre>
<p>You can do this going forward in time from the epoch time as well. Remember, we also want to grab 23:59:59 on the Saturday after the epoch timestamp you now have:</p>
<pre>&gt;&gt;&gt; saturday_night = midnight + ((5 - dow+1) * 86400) - 1
&gt;&gt;&gt; time.ctime(saturday_night)
'Sat May 22 23:59:59 2010'
&gt;&gt;&gt;
</pre>
<p>And that&#8217;s how you do date manipulation using *only* the time module. Elegant,no?</p>
<p>No. Not really.</p>
<p>Unfortunately, the alternatives also aren&#8217;t the most elegant in the world, imho. So let&#8217;s try doing this all another way, using the datetime module and timedelta objects.</p>
<h4>Now with datetime!</h4>
<p>The documentation for the datetime module says:</p>
<p>&#8220;While date and time arithmetic is supported, the focus of the implementation is on efficient member extraction for output formatting and manipulation.&#8221;</p>
<p>Hm. Sounds a lot like what the time module functions do. Some conversion here or there, but no real arithmetic support. We had to pretty much do it ourselves mucking about with epoch integer values. So what&#8217;s this buy us over the time module?</p>
<p>Let&#8217;s try to do our original task using the datetime module. We&#8217;re going to start with an epoch timestamp, and calculate the values for the previous Sunday at midnight, and the following Saturday at 23:59:59.</p>
<p>The first thing I had a hard time finding was a way to deal with the notion of a &#8220;week&#8221;. I thought I&#8217;d found it in &#8216;date.timetuple()&#8217;, which help(date.timetuple) says is &#8220;compatible with time.localtime()&#8221;. I guess they must mean that the output is the same as time.localtime(), because I can&#8217;t find any other way in which it is similar. Running time.localtime() with no arguments returns a time_struct object for the current time. date.timetuple() requires arguments or it&#8217;ll throw an error, and to make you extra frustrated, the arguments it takes aren&#8217;t in the docs or the help() output.</p>
<p>So maybe they mean it takes the same arguments as time.localtime(), eh? Not so much &#8212; time.localtime() takes an int representing an epoch timestamp. Trying to feed an int to date.timetuple throws an error saying it requires a &#8216;date&#8217; object.</p>
<p>So, the definition of &#8220;compatible&#8221; is a little unclear to me in this context.</p>
<p>So here I&#8217;ve set about finding today, then &#8220;last saturday&#8221;, and then &#8220;the sunday before the last saturday&#8221;:</p>
<pre class="brush: python;">
def get_last_whole_week(today=None):
    # a date object
    date_today = today or datetime.date.today()

    # day 0 is Monday. Sunday is 6.
    dow_today = date_today.weekday()

    if dow_today == 6:
        days_ago_saturday = 1
    else:
    # If day between 0-5, to get last saturday, we need to go to day 0 (Monday), then two more days.
        days_ago_saturday = dow_today + 2

    # Make a timedelta object so we can do date arithmetic.
    delta_saturday = datetime.timedelta(days=days_ago_saturday)

    # saturday is now a date object representing last saturday
    saturday = date_today - delta_saturday

    # timedelta object representing '6 days'...
    delta_prevsunday = datetime.timedelta(days=6)

    # Making a date object. Subtract the days from saturday to get &quot;the Sunday before that&quot;.
    prev_sunday = saturday - delta_prevsunday
</pre>
<p>This gets me date objects representing the start and end time of my reporting range&#8230; sort of. I need them in epoch format, and I need to specifically start at midnight on Sunday and end on 23:59:59 on Saturday night. Sunday at midnight is no problem: timetuple() sets time elements to 0 anyway. For Saturday night, in epoch format, I should probably just calculate a date object for two Sundays a week apart, and subtract one second from one of them to get the last second of the previous Saturday.</p>
<p>Here&#8217;s the above function rewritten to return a tuple containing the start and end dates of the previous week. It can optionally be returned in epoch format, but the default is to return date objects.</p>
<pre class="brush: python;">
def get_last_whole_week(today=None, epoch=False):
    # a date object
    date_today = today or datetime.date.today()
    print &quot;date_today: &quot;, date_today

    # By default day 0 is Monday. Sunday is 6.
    dow_today = date_today.weekday()
    print &quot;dow_today: &quot;, dow_today

    if dow_today == 6:
        days_ago_saturday = 1
    else:
        # If day between 0-5, to get last saturday, we need to go to day 0 (Monday), then two more days.
        days_ago_saturday = dow_today + 2
    print &quot;days_ago_saturday: &quot;, days_ago_saturday
    # Make a timedelta object so we can do date arithmetic.
    delta_saturday = datetime.timedelta(days=days_ago_saturday)
    print &quot;delta_saturday: &quot;, delta_saturday
    # saturday is now a date object representing last saturday
    saturday = date_today - delta_saturday
    print &quot;saturday: &quot;, saturday
    # timedelta object representing '6 days'...
    delta_prevsunday = datetime.timedelta(days=6)
    # Making a date object. Subtract the 6 days from saturday to get &quot;the Sunday before that&quot;.
    prev_sunday = saturday - delta_prevsunday

    # we need to return a range starting with midnight on a Sunday, and ending w/ 23:59:59 on the
    # following Saturday... optionally in epoch format.

    if epoch:
        # saturday is date obj = 'midnight saturday'. We want the last second of the day, not the first.
        saturday_epoch = time.mktime(saturday.timetuple()) + 86399
        prev_sunday_epoch = time.mktime(prev_sunday.timetuple())
        last_week = (prev_sunday_epoch, saturday_epoch)
    else:
        saturday_str = saturday.strftime('%Y-%m-%d')
        prev_sunday_str = prev_sunday.strftime('%Y-%m-%d')
        last_week = (prev_sunday_str, saturday_str)
    return last_week
</pre>
<p>It would be easier to just have some attribute for datetime objects that lets you set the first day of the week to be Sunday instead of Monday. It wouldn&#8217;t completely alleviate every conceivable issue with calculating dates, but it would be a help. The calendar module has a setfirstweekday() method that lets you set the first weekday to whatever you want. I gather this is mostly for formatting output of matrix calendars, but it would be useful if it could be used in date calculations as well. Perhaps I&#8217;ve missed something? Clues welcome.</p>
<h3>Mission 2: Calculate the Prior Month&#8217;s Start and End Dates</h3>
<p>This should be easy. What I hoped would happen is I&#8217;d be able to get today&#8217;s date, and then create a timedelta object for &#8217;1 month&#8217;, and subtract, having Python take care of things like changing the year when the current month is January. Calculating this yourself is a little messy: you can&#8217;t just use &#8220;30 days&#8221; or &#8220;31 days&#8221; as the length of a month, because:</p>
<ol>
<li>&#8220;January 31&#8243; &#8211; &#8220;30 days&#8221; = &#8220;January 1&#8243; &#8212; not the previous month.</li>
<li>&#8220;March 1&#8243; &#8211; &#8220;31 days&#8221; = &#8220;January 30&#8243; &#8212; also not the previous month.</li>
</ol>
<p>Instead, what I did was this:</p>
<ol>
<li>create a datetime object for the first day of the current month (hard coding the &#8216;day&#8217; argument)</li>
<li>used a timedelta object to subtract a day, which gives me a datetime object for the last day of the prior month (with year changed for me if needed),</li>
<li>used that object to create a datetime object for the first day of the prior month (again hardcoding the &#8216;day&#8217; argument)</li>
</ol>
<p>Here&#8217;s some code:</p>
<pre class="brush: python;">
today = datetime.datetime.today()
first_day_current = datetime.datetime(today.year, today.month, 1)
last_day_previous = first_day_current - datetime.timedelta(days=1)
first_day_previous = datetime.datetime(last_day_previous.year, last_day_previous.month, 1)
print 'Today: ', today
print 'First day of this month: ', first_day_current
print 'Last day of last month: ', last_day_previous
print 'First day of last month: ', first_day_previous
</pre>
<p>This outputs:</p>
<pre>Today:  2010-07-06 09:57:33.066446
First day of this month:  2010-07-01 00:00:00
Last day of last month:  2010-06-30 00:00:00
First day of last month:  2010-06-01 00:00:00
</pre>
<p>Not nearly as onerous as the week start/end range calculations, but I kind of thought that between all of these modules we have that one of them would be able to find me the start and end of the previous month. The raw material for creating this is, I suspect, buried somewhere in the source code for the calendar module, which can tell you the start and end dates for a month, but can&#8217;t do any date calculations to give you the previous month. The datetime module can do calculation, but it can&#8217;t tell you the start and end dates for a month. The datetime.timedelta object&#8217;s largest granularity is &#8216;week&#8217; if memory serves, so you can&#8217;t just do &#8216;timedelta(months=1)&#8217;, because the deltas are all converted internally to a <em>fixed number</em> of days, seconds, or milliseconds, and a month isn&#8217;t a fixed number of any of them.</p>
<h3>Converge!</h3>
<p>While I could probably go ahead and use dateutil, which is really darn flexible, I&#8217;d rather be able to do this without a third-party module. Also, dateutil&#8217;s flexibility is not without it&#8217;s complexity, either. It&#8217;s not an insurmountable task to learn, but it&#8217;s not like you can directly transfer your experience with the built-in modules to using dateutil.</p>
<p>I don&#8217;t think merging all of the time-related modules in Python would be necessary or even desirable, really, but I haven&#8217;t thought deeply about it. Perhaps a single module <em>could</em> provide a superclass for the various time-related objects currently spread across three modules, and they could share some base level functionality. Hard to conceive of a timedelta object not floating alone in space in that context, but alas, I&#8217;m thinking out loud. Perhaps a dive into the code is in order.</p>
<p>What have you had trouble doing with dates and times in Python? What docs have I missed? What features are completely missing from Python in terms of time manipulation that would actually be useful enough to warrant inclusion in the collection of included batteries? Let me know your thoughts.</p>
<script type="text/javascript">
  addthis_url    = 'http%3A%2F%2Fwww.protocolostomy.com%2F2010%2F07%2F06%2Fpython-date-manipulation%2F';
  addthis_title  = 'Python+Date+Manipulation';
  addthis_pub    = 'jonesy';
</script><script type="text/javascript" src="http://s7.addthis.com/js/addthis_widget.php?v=12" ></script>

<p><a href="http://feedads.g.doubleclick.net/~a/8hhtDCqsIX3fwQgv3aBgBb9RfZA/0/da"><img src="http://feedads.g.doubleclick.net/~a/8hhtDCqsIX3fwQgv3aBgBb9RfZA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/8hhtDCqsIX3fwQgv3aBgBb9RfZA/1/da"><img src="http://feedads.g.doubleclick.net/~a/8hhtDCqsIX3fwQgv3aBgBb9RfZA/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=jUFOBc-XfdI:PyFM86Si7zI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=jUFOBc-XfdI:PyFM86Si7zI:bcOpcFrp8Mo"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=bcOpcFrp8Mo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=jUFOBc-XfdI:PyFM86Si7zI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?i=jUFOBc-XfdI:PyFM86Si7zI:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/MusingsOfAnAnonymousGeek/~4/jUFOBc-XfdI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2010/07/06/python-date-manipulation/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<feedburner:origLink>http://www.protocolostomy.com/2010/07/06/python-date-manipulation/</feedburner:origLink></item>
		<item>
		<title>Brain Fried Over NoSQL</title>
		<link>http://feedproxy.google.com/~r/MusingsOfAnAnonymousGeek/~3/tcZLUqjzCLw/</link>
		<comments>http://www.protocolostomy.com/2010/06/26/brain-fried-over-nosql/#comments</comments>
		<pubDate>Sun, 27 Jun 2010 03:16:02 +0000</pubDate>
		<dc:creator>m0j0</dc:creator>
				<category><![CDATA[Big Ideas]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=799</guid>
		<description><![CDATA[So, I&#8217;m working on a pet project. It&#8217;s in stealth mode. Just kidding &#8212; I don&#8217;t believe in stealth mode It&#8217;s a twitter analytics dashboard that actually does useful things with the mountains of data available from the various Twitter APIs. I&#8217;m writing it in Python using Tornado. Here&#8217;s the first mockup I ever did [...]]]></description>
			<content:encoded><![CDATA[<p>So, I&#8217;m working on a pet project. It&#8217;s in stealth mode. Just kidding &#8212; I don&#8217;t believe in stealth mode <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>It&#8217;s a twitter analytics dashboard that actually does useful things with the mountains of data available from the various Twitter APIs. I&#8217;m writing it in Python using Tornado. Here&#8217;s the first mockup I ever did for it, just like 2 nights ago:</p>
<p><a href="http://www.protocolostomy.com/wp-content/uploads/2010/06/tweetdash-mockup.png"><img class="alignleft size-medium wp-image-800" title="mockup" src="http://www.protocolostomy.com/wp-content/uploads/2010/06/tweetdash-mockup-300x214.png" alt="" width="413" height="294" /></a> It&#8217;s already a lot of fun. I&#8217;ve worked with Tornado before and like it a lot. I have most of the base infrastructure questions answered, because this is a pet project and they&#8217;re mostly easy and in some sense &#8220;don&#8217;t matter&#8221;. But that&#8217;s what has me stuck.</p>
<h3>It Doesn&#8217;t Matter</h3>
<p>It&#8217;s true. Past a certain point, belaboring choices of what tools to use where is pointless and is probably premature optimization. I&#8217;ve been working with startups for the past few years, and I&#8217;m painfully aware of what happens when a company takes too long to react to their popularity. I want to architect around that at the start, but I&#8217;m resisting. It&#8217;s a pet project.</p>
<p>But if it doesn&#8217;t matter, that means I can choose tools that are going to be fun to dig into and learn about. I&#8217;ve been so busy writing code to help avoid or buffer impact to the database that I haven&#8217;t played a whole lot with the NoSQL choices out there, and there are tons of them. And they all have a different world view and a unique approach to providing solutions to what I see as somewhat different problems.</p>
<h3>Why NoSQL?</h3>
<p>Why not? I&#8217;ve been working with relational database systems since 1998. I worked on large data reporting projects, a couple of huge data warehousing projects, financial transaction systems, I worked for Sybase as a consulting DBA and project manager for a while, I was into MySQL and PostgreSQL by 2000, used them in production environments starting around 2001-02&#8230; I understand them fairly well. I also understand BDB and other &#8220;flat-file&#8221; databases and object stores. SQLite has become unavoidable in the past few years as well. It&#8217;s not like I don&#8217;t understand the compromises I&#8217;m making going to a NoSQL system.</p>
<p>There&#8217;s a good bit of talk from the RDBMS camp (seriously, why do they need their own camp?) about why NoSQL is bad. Lots of people who know me  would put me in the RDBMS camp, and I&#8217;m telling you not to cry yourself to sleep out of guilt over a desire to get to know these systems. They&#8217;re interesting, and they solve some huge issues surrounding scalability with greater ease than an RDBMS.</p>
<p>Like what? Well, cost for one. If I could afford Oracle I&#8217;d sooner use that than go NoSQL in all likelihood. I can&#8217;t afford it. Not even close. Oracle might as well charge me a small planet for their product. It&#8217;s great stuff, but out of reach. And what about sharding? Sharding a relational database sucks, and to try to hide the fact that it sucks requires you to pile on all kinds of other crap like query proxies, pools, and replication engines, all in an effort to make this beast do something it wasn&#8217;t meant to do: scale beyond a single box. All this stuff also attempts to mask the reality that you&#8217;ve also thrown your hands in the air with respect to at least 2 letters that make up the ACID acronym. What&#8217;s an RDBMS buying you at that point? Complexity.</p>
<p>And there&#8217;s another cost, by the way: no startup I know has the kind of enormous hardware that an enterprise has. They have access to commodity hardware. Pizza boxes. Don&#8217;t even get me started on storage. I&#8217;ve yet to see SSD or flash storage at a startup. I currently work at MyYearbook.com, and there are some pretty hefty database servers there, but it can hardly be called a startup anymore. Hell, they&#8217;re even profitable! <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h3>Where Do I Start?</h3>
<p>One nice thing about relationland is I know the landscape pretty well. Going to NoSQL is like dropping me in a country I&#8217;ve never heard of where I don&#8217;t really speak the language. I have some familiarity with key-value stores from dealing with BDB and Memcache, and I&#8217;ve played with MongoDB a bit (using pymongo), but that&#8217;s just the tip of the iceberg.</p>
<p>I heard my boss mention Tokyo Tyrant a few times, so I looked into it. It seems to be one of the more obscure solutions out there from the standpoint of adoption, community, documentation, etc., but it does appear to be very capable on a technical level. However, my application is going to be number-heavy, and I&#8217;m not going to need to own all of the data required to provide the service. I can probably get away with just incrementing counters in Memcache for some of this work. For persistence I need something that will let me do aggregation *FAST* without having to create aggregation tables, ideally. Using a key/value store for counters really just seems like a no-brainer.</p>
<p>That said, I think what I&#8217;ve decided to do, since it doesn&#8217;t matter, is punt on this decision in favor of getting a working application up quickly.</p>
<h3>MySQL</h3>
<p>Yup. I&#8217;m going to pick one or two features of the application to implement as a &#8216;first cut&#8217;, and back them with a MySQL database. I know it well, Tornado has a built-in interface for it, and it&#8217;s not going to be a permanent part of the infrastructure (otherwise I&#8217;d choose PostgreSQL in all likelihood).</p>
<p>To be honest, I don&#8217;t think the challenge in bringing this application to life are really related to the data model or the engine/interface used to access it (though if I&#8217;m lucky that&#8217;ll be a major part of <em>keeping</em> it alive). No, the real problem I&#8217;m faced with is completely unrelated to these considerations&#8230;</p>
<h3>Twitter&#8217;s API Service</h3>
<p>Not the API itself, per se, but the service providing access to it, and the way it&#8217;s administered, is going to be a huge challenge. It&#8217;s not just the Twitter website that&#8217;s inconsistent, the API service goes right along. Not only that, but the type of data I really need to make this application useful isn&#8217;t immediately available from the API as far as I can tell.</p>
<p>Twitter maintains rate limits on the API. You can only make so many calls over so short a period of time. That alone makes providing an application like this to a lot of people a bit of a challenge. Compounding the issue is that, when there are failwhales washing up on the shores, those limits can be dynamically decreased. Ugh.</p>
<p>I guess it&#8217;s not a project for the faint of heart, but it&#8217;ll drive home some golden rules that are easy to neglect in other projects, like planning for failure (of both my application, and Twitter). Also, it&#8217;ll be a lot of fun.</p>
<script type="text/javascript">
  addthis_url    = 'http%3A%2F%2Fwww.protocolostomy.com%2F2010%2F06%2F26%2Fbrain-fried-over-nosql%2F';
  addthis_title  = 'Brain+Fried+Over+NoSQL';
  addthis_pub    = 'jonesy';
</script><script type="text/javascript" src="http://s7.addthis.com/js/addthis_widget.php?v=12" ></script>

<p><a href="http://feedads.g.doubleclick.net/~a/K8LZbhxv7SuzCmHjWJsLDElMEnA/0/da"><img src="http://feedads.g.doubleclick.net/~a/K8LZbhxv7SuzCmHjWJsLDElMEnA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/K8LZbhxv7SuzCmHjWJsLDElMEnA/1/da"><img src="http://feedads.g.doubleclick.net/~a/K8LZbhxv7SuzCmHjWJsLDElMEnA/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=tcZLUqjzCLw:I2h8q82LGnw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=tcZLUqjzCLw:I2h8q82LGnw:bcOpcFrp8Mo"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=bcOpcFrp8Mo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=tcZLUqjzCLw:I2h8q82LGnw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?i=tcZLUqjzCLw:I2h8q82LGnw:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/MusingsOfAnAnonymousGeek/~4/tcZLUqjzCLw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2010/06/26/brain-fried-over-nosql/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.protocolostomy.com/2010/06/26/brain-fried-over-nosql/</feedburner:origLink></item>
		<item>
		<title>Why Open Shop In California?</title>
		<link>http://feedproxy.google.com/~r/MusingsOfAnAnonymousGeek/~3/Bo4cZLbM-64/</link>
		<comments>http://www.protocolostomy.com/2010/06/03/why-open-shop-in-california/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 12:44:00 +0000</pubDate>
		<dc:creator>m0j0</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Services]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=795</guid>
		<description><![CDATA[DISCLAIMER: I live on the East Coast, so these are perceptions and opinions that I don&#8217;t put forth as facts. I&#8217;m more asking a question to start a dialog than professing knowledge. So, I just heard a report claiming that there are more IT jobs than techs to fill them in Southern California. Anyone who [...]]]></description>
			<content:encoded><![CDATA[<p>DISCLAIMER: I live on the East Coast, so these are perceptions and opinions that I don&#8217;t put forth as facts. I&#8217;m more asking a question to start a dialog than professing knowledge.</p>
<p>So, I just heard a report claiming that there are more IT jobs than techs to fill them in Southern California. Anyone who ever reads a tech job board and/or TechCrunch has also no doubt taken note that a vast majority of startups seem to be starting up there, and that there are just a metric asston of jobs there anyway. </p>
<p>This boggles my mind. This is a place with an extremely high cost of living, making labor more expensive. At the same time, aren&#8217;t there rolling power outages in CA? Does that not effect corporations or something? Do they just move their datacenters across the border to another state? </p>
<p>Between what I would think is an amazingly high labor cost and what I would think is an unfavorable place in terms of simple things like availability of power, I would think more places would look elsewhere for expansion or startups. </p>
<p>I live within spitting distance of at least 5 universities with engineering departments that I think would rate at the very least &#8220;solid&#8221;, many would rate better. I would guess that I could get to any Ivy League school in 6 hours or less, driving (3 are within an hour of my NJ home). MIT and Stevens are very good non-Ivy schools, and lots of other ones like Rutgers, NJIT, Penn State, NYU, and lots more are here, and those are just a few of the ones between NYC and Philadelphia, which are less than 2 hours apart. So&#8230;. there&#8217;s a labor pool here. </p>
<p>Is it tax breaks? Some aspect of the political atmosphere? Transportation? Is San Francisco such a clean, safe, friendly city that you just deal with the nonsense to live there? </p>
<p>What&#8217;s your take on this? </p>
<script type="text/javascript">
  addthis_url    = 'http%3A%2F%2Fwww.protocolostomy.com%2F2010%2F06%2F03%2Fwhy-open-shop-in-california%2F';
  addthis_title  = 'Why+Open+Shop+In+California%3F';
  addthis_pub    = 'jonesy';
</script><script type="text/javascript" src="http://s7.addthis.com/js/addthis_widget.php?v=12" ></script>

<p><a href="http://feedads.g.doubleclick.net/~a/ajAkrRXx-McF5RMUuwDJtRIazkA/0/da"><img src="http://feedads.g.doubleclick.net/~a/ajAkrRXx-McF5RMUuwDJtRIazkA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ajAkrRXx-McF5RMUuwDJtRIazkA/1/da"><img src="http://feedads.g.doubleclick.net/~a/ajAkrRXx-McF5RMUuwDJtRIazkA/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=Bo4cZLbM-64:Nkqww0LFjdU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=Bo4cZLbM-64:Nkqww0LFjdU:bcOpcFrp8Mo"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=bcOpcFrp8Mo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=Bo4cZLbM-64:Nkqww0LFjdU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?i=Bo4cZLbM-64:Nkqww0LFjdU:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/MusingsOfAnAnonymousGeek/~4/Bo4cZLbM-64" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2010/06/03/why-open-shop-in-california/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		<feedburner:origLink>http://www.protocolostomy.com/2010/06/03/why-open-shop-in-california/</feedburner:origLink></item>
		<item>
		<title>Python IDE Frustration</title>
		<link>http://feedproxy.google.com/~r/MusingsOfAnAnonymousGeek/~3/a19gxqgf_f0/</link>
		<comments>http://www.protocolostomy.com/2010/05/13/python-ide-frustration/#comments</comments>
		<pubDate>Fri, 14 May 2010 02:22:32 +0000</pubDate>
		<dc:creator>m0j0</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=777</guid>
		<description><![CDATA[I didn&#8217;t think I was looking for a lot in an IDE. Turns out what I want is impossibly hard to find. In the past 6 months I&#8217;ve tried (or tried to try): Komodo Edit Eclipse w/ PyDev PyCharm (from the first EAP build to&#8230; yesterday) Wingware Textmate Wingware First, let&#8217;s get Wingware out of [...]]]></description>
			<content:encoded><![CDATA[<p>I didn&#8217;t think I was looking for a lot in an IDE. Turns out what I want is impossibly hard to find.</p>
<p>In the past 6 months I&#8217;ve tried (or tried to try):</p>
<ul>
<li>Komodo Edit</li>
<li>Eclipse w/ PyDev</li>
<li>PyCharm (from the first EAP build to&#8230; yesterday)</li>
<li>Wingware</li>
<li>Textmate</li>
</ul>
<h3>Wingware</h3>
<p>First, let&#8217;s get Wingware out of the way. I&#8217;m on a Mac, and if you&#8217;re not going to develop for the Mac, I&#8217;m not going to pay you hundreds of dollars for your product. Period. I don&#8217;t even use free software that requires X11. Lemme know when you figure out that coders like Macs and I&#8217;ll try Wingware.</p>
<h3>Komodo Edit</h3>
<p>Well, I wanted to try the IDE but I downloaded it, launched it once for 5 minutes (maybe less), forgot about it, and now my trial is over. I&#8217;ll email sales about this tomorrow. In the meantime, I use Komodo Edit.</p>
<p>Komodo Edit is pretty nice. One thing I like about it is that it doesn&#8217;t really go overboard forcing its world view down my throat. If I&#8217;m working on bunny, which is a one-file Python project I keep in a git repository, I don&#8217;t have to figure out their system for managing projects. I can just &#8220;Open File&#8221; and use it as a text editor.</p>
<p>It has &#8220;ok&#8221; support for Vi key bindings, and it&#8217;s not a plugin: it&#8217;s built in. The support has some annoying limitations, but for about 85% of what I need it to do it&#8217;s fine. One big annoyance is that I can&#8217;t write out a file and assign it a name (e.g. &#8216;:w /some/filename.txt&#8217;). It&#8217;s not supported.</p>
<p>Komodo Edit, unless I missed it, doesn&#8217;t integrate with Git, and doesn&#8217;t offer a Python console. Its capabilities in the area of collaboration in general are weak. I don&#8217;t absolutely have to have them, but things like that are nice for keeping focused and not having to switch away from the window to do anything else, so ideally I could get an IDE that has this. I believe Komodo IDE has these things, so I&#8217;m looking forward to trying it out.</p>
<p>Komodo is pretty quick compared to most IDEs, and has always been rock solid stable for me on both Mac and Linux, so if I&#8217;m not in the mood to use Vim, or I need to work on lots of files at once, Komodo Edit is currently my &#8216;go-to&#8217; IDE.</p>
<h3>PyCharm</h3>
<p>PyCharm doesn&#8217;t have an officially supported release. I&#8217;ve been using Early Adopter Previews since the first one, though. When it&#8217;s finally stable I&#8217;m definitely going to revisit it, because to be honest&#8230; it&#8217;s kinda dreamy.</p>
<p>Git integration is very good. I used it with GitHub without incident for some time, but these are early adopter releases, and things happen: two separate EAP releases of PyCharm made my project files completely disappear without warning, error, or any indication that anything was wrong at all. Of course, this is git, so running &#8216;git checkout -f&#8217; brought things back just fine, but it&#8217;s unsettling, so now I&#8217;m just waiting for the EAP to be over with and I&#8217;ll check it out when it&#8217;s done.</p>
<p>I think for the most part, PyCharm nails it. This is the IDE I want to be using assuming the stability issues are worked out (and I don&#8217;t have reason to believe they won&#8217;t be). It gives me a Python console, VCS integration, a good class and project browser, some nice code analytics, and more complex syntax checking that &#8220;just works&#8221; than I&#8217;ve seen elsewhere. It&#8217;s a pretty handsome, very intuitive IDE, and it leverages an underlying platform whose plugins are available to PyCharm users as well, so my Vim keys are there (and, by the way, the IDEAVim plugin is the most advanced Vim support I&#8217;ve seen in any IDE, hands down).</p>
<h3>Eclipse with PyDev</h3>
<p>One thing I learned from using PyCharm and Eclipse is that where tools like this are concerned, I really prefer a specialized tool to a generic one with plugins layered on to provide the necessary functionality. Eclipse with PyDev really feels to me like a Java IDE that you have to spend time laboriously chiseling, drilling, and hammering to get it to do what you need if you&#8217;re not a Java developer. The configuration is extremely unintuitive, with a profuse array of dialogs, menus, options, options about options and menus, menus about menus and options&#8230; it never seems to end.</p>
<p>All told, I&#8217;ve probably spent the equivalent of 2 working days mucking with Eclipse configuration, and I&#8217;ve only been able to get it &#8220;pretty close&#8221; to where I want it. The Java-loving underpinnings of the Eclipse platform simply cannot be suppressed, while things I had to layer on with plugins don&#8217;t show up in the expected places.</p>
<p>Add to this Eclipse&#8217;s world-view, which reads something like &#8220;there is no filesystem tree: only projects&#8221;, and you have a really damned annoying IDE. I&#8217;ve tried on and off for over a year to make friends with Eclipse because of the good things I hear about PyDev, but it just feels like a big hacky, duct-taped mess to me, and if PyCharm has proven anything to me, it&#8217;s that building a language specific IDE on an underlying platform devoted to Java doesn&#8217;t have to be like this. When I finally got it to some kind of usable point, and after going through the &#8220;fonts and colors&#8221; maze, it turns out the syntax highlighting isn&#8217;t really all that great!</p>
<p>A quick word about Vi key bindings in Eclipse: it&#8217;s not a pretty picture, but the best I&#8217;ve been able to find is a free tool called Vrapper. It&#8217;s not bad. I could get by with Vrapper, but I don&#8217;t believe it&#8217;s as mature and evolved as IDEAVim plugin in PyCharm.</p>
<p>So, I&#8217;ll probably turn back to Eclipse for Java development (I&#8217;m planning on taking on a personal Android project), but I think I&#8217;ve given up on it for anything not Java-related.</p>
<h3>Vim</h3>
<p>Vim is technically &#8216;just an editor&#8217;, but it has some nice benefits, and with the right plugins, it can technically do all of the things a fancy IDE can. I use the taglist plugin to provide the project and class browser functionality, and the kicker here is that you can actually switch to the browser pane, type &#8216;/&#8217; and the object or member you&#8217;re looking for, and jump to it in a flash. It&#8217;s also the most complete Vim key binding implementation available <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>The big win for me in using Vim though is remote work. Though I&#8217;d rather do all of my coding locally, there are times when I really have to write code on remote machines, and I don&#8217;t want to go through the rigmarole of coding, pushing my changes, going to my terminal, pulling down the changes, testing, failing, fixing the code on my machine, pushing my changes, pulling my changes&#8230; ugh.</p>
<p>So why not just use Vim? I could do it. I&#8217;ve been using Vim for many years and am pretty good with it, but I just feel like separating my coding from my terminal whenever I can is a good thing. I don&#8217;t want my code to look like my terminal, nor do I want my terminal to look like my IDE theme. I&#8217;m SUPER picky about fonts and colors in my IDE, and I&#8217;m not that picky about them in my terminal. I also want the option of using my mouse while I&#8217;m coding, mostly to scroll, and getting that to work on a Mac in Terminal.app isn&#8217;t as simple as you might expect (and I&#8217;m not a fan of iTerm&#8230; and its ability to do this comes at a cost as well).</p>
<p>MacVim is nice, solves the separation of Terminal and IDE, and I might give it a more serious try, but let&#8217;s face it, it&#8217;s just not an IDE. Code completion is still going to be mediocre, the interface is still going to be terminal-ish&#8230; I just don&#8217;t know. One thing I really love though is the taglist plugin. I think if I could just find a way to embed a Python console along the bottom of MacVim I might be sold.</p>
<p>One thing I absolutely love about Vim, the thing that Vim gets right that none of the IDEs get is colorschemes: MacVim comes with like 20 or 30 colorschemes! And you can download more on the &#8216;net! The other IDEs must lump colorscheme information into the general preferences or something, because you can&#8217;t just download a colorscheme as far as I&#8217;ve seen. The IDE with the worst color/font configuration? Eclipse &#8211; the one all my Python brethren seem to rave about. That is so frustrating. Some day I&#8217;ll make it to PyCon and someone will show me the kool-aid I guess.</p>
<h3>The Frustrating Conclusion</h3>
<p>PyCharm isn&#8217;t soup yet, Wingware is all but ignoring the Mac platform, Eclipse is completely wrong for my brain and I don&#8217;t know how anyone uses it for Python development, Komodo Edit is rock solid but lacking features, and Komodo IDE is fairly pricey and a 30-day trial is always just really annoying (and I kinda doubt it beats PyCharm for Python-specific development). MacVim is a stand-in for a real IDE and it does the job, but I really want more&#8230; integration! I also don&#8217;t like maintaining the plugins and colorschemes and *rc files and ctags, and having to understand its language and all that.</p>
<p>I don&#8217;t cover them here, but I&#8217;ve tried a bunch of the Linux-specific Python IDEs as well, and I didn&#8217;t like a single one of them at all. At some point I&#8217;ll spend more time with those tools to see if I missed something crucial that, once learned, might make it hug my brain like a warm blanket (and make me consider running Linux on my desktop again, something I haven&#8217;t done on a regular ongoing basis in about 4 years).</p>
<p>So&#8230; I don&#8217;t really have an IDE yet. I *did* however just realize that the laptop I&#8217;m typing on right now has never had a Komodo IDE install, so I&#8217;m off to test it now. Wish me luck!</p>
<script type="text/javascript">
  addthis_url    = 'http%3A%2F%2Fwww.protocolostomy.com%2F2010%2F05%2F13%2Fpython-ide-frustration%2F';
  addthis_title  = 'Python+IDE+Frustration';
  addthis_pub    = 'jonesy';
</script><script type="text/javascript" src="http://s7.addthis.com/js/addthis_widget.php?v=12" ></script>

<p><a href="http://feedads.g.doubleclick.net/~a/_hesnNxWVlnhB9V5yrvUihfGazM/0/da"><img src="http://feedads.g.doubleclick.net/~a/_hesnNxWVlnhB9V5yrvUihfGazM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/_hesnNxWVlnhB9V5yrvUihfGazM/1/da"><img src="http://feedads.g.doubleclick.net/~a/_hesnNxWVlnhB9V5yrvUihfGazM/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=a19gxqgf_f0:pvks5cflF8s:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=a19gxqgf_f0:pvks5cflF8s:bcOpcFrp8Mo"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?d=bcOpcFrp8Mo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?a=a19gxqgf_f0:pvks5cflF8s:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/MusingsOfAnAnonymousGeek?i=a19gxqgf_f0:pvks5cflF8s:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/MusingsOfAnAnonymousGeek/~4/a19gxqgf_f0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2010/05/13/python-ide-frustration/feed/</wfw:commentRss>
		<slash:comments>42</slash:comments>
		<feedburner:origLink>http://www.protocolostomy.com/2010/05/13/python-ide-frustration/</feedburner:origLink></item>
	</channel>
</rss>
