<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xml:base="http://whijo.net" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
 <title>lazyweb</title>
 <link>http://whijo.net/taxonomy/term/24/feed</link>
 <description>The taxonomy view with a depth of 0.</description>
 <language>en</language>
<item>
 <title>Python and cybersmart Caps</title>
 <link>http://whijo.net/blog/brad/2007/06/24/python-and-cybersmart-caps.html</link>
 <description>I recently got DSL at home (&lt;a href=&quot;http://nml.ru.ac.za/blog/brad/2007/05/24/one-goes-out-telkom.html&quot;&gt;after 22 working days&lt;/a&gt;), and signed up with a local ISP (&lt;a href=&quot;http://www.cybersmart.co.za&quot;&gt;cybersmart&lt;/a&gt; - you can tell them bwhittington@cybersmart.co.za referred you) because it was the &lt;a href=&quot;http://www.hellkom.co.za/ispprices/adsl-3gb.php&quot;&gt;cheapest 3 Gig cap&lt;/a&gt; available. What I also like about them is they provide a very simple web page that helps you keep track of your usage. I knew a bit of python, and I wanted to further my skills, so I decided to tap out a python script to bring my cap usage to the desktop. The result:

&lt;span class=&quot;inline&quot;&gt;&lt;a href=&quot;http://whijo.net/files/cybersmart-cap.png&quot; class=&quot;inline-image-link&quot; title=&quot;View: cybersmart-cap.png&quot; rel=&quot;lightbox[gp_inline]&quot;&gt;&lt;img src=&quot;http://whijo.net/files/imagecache/inline_resize/files/cybersmart-cap.png&quot; alt=&quot;cybersmart-cap.png&quot; title=&quot;cybersmart-cap.png&quot;  class=&quot;inline&quot; /&gt;&lt;/a&gt;&lt;/span&gt;
&lt;!--break--&gt;

What this re-iterated for me is that python is awesome, linux is awesome, gnome is awesome, and python is awesome. You can get python wrappers for just about everything, and more and more programs include python as an avenue to build extensions (my first non-django, python project was a rhythmbox plugin that pauses the music when your screensaver turns on). 

So I started out on the problem. It was a pretty straightforward issue: download the html from cybersmart, walk the &lt;abbr title=&quot;Document Object Model&quot;&gt;DOM&lt;/abbr&gt;, grab the elements with the relevant data, typecast the data to a floating point number, and, for cream, calculate daily averages (per day usage, per day remaining). Finally, display the data. For this little project I used urllib, pyxml, pynotify (a thin wrapper around libnotify), datetime and time (you can download the full file as an attachment to this blog post).

We start with the data, the cybersmart page looks like this:

&lt;span class=&quot;inline&quot;&gt;&lt;a href=&quot;http://whijo.net/files/cap-summary.png&quot; class=&quot;inline-image-link&quot; title=&quot;View: cap-summary.png&quot; rel=&quot;lightbox[gp_inline]&quot;&gt;&lt;img src=&quot;http://whijo.net/files/imagecache/inline_resize/files/cap-summary.png&quot; alt=&quot;cap-summary.png&quot; title=&quot;cap-summary.png&quot;  class=&quot;inline&quot; /&gt;&lt;/a&gt;&lt;/span&gt;

The relevant bits of information are the &quot;Used for this month&quot; and &quot;Total left for month&quot;. Luckily these are stored in elements with class names that are relevant (although they do reuse the same class name for multiple things, instead of doing a class=&quot;used usedTotal&quot; and a class=&quot;remaining remainingTotal&quot;, and styling the relevant classes, while getting the semantic meaning, and visual identity across). 

So, we download the file (sending relevant log in details as a POST), and send it to the HtmlReader class of pyxml:
&lt;pre&gt;&lt;code&gt;print(&quot;Downloading HTML&quot;)
data = urllib.urlencode(
  {   &quot;accountName&quot;:&quot;account@cybersmart.co.za&quot;,
      &quot;password&quot;:&quot;password&quot;,
      &quot;login&quot;:&quot;login&quot;})
f = urllib.urlopen(
      &quot;http://www.cybersmart.co.za/getAccountDetails.cgi&quot;,
      data
    )
doc = f.read()
f.close()
reader= HtmlLib.Reader()
&lt;/code&gt;&lt;/pre&gt;

Then we parse the document, and walk the DOM tree, pulling out relevant info (sidebar: I couldn&#039;t do this more efficiently than pulling out all the td&#039;s and then checking each class entry, the getElementByClass doesn&#039;t seem to work out properly?? I also cheat because there are multiple savedTotal elements, but I am only worried about the last one):
&lt;pre&gt;&lt;code&gt;print(&quot;Parsing Document&quot;)
dom = reader.fromString(doc)

print(&quot;Walking the tree&quot;)
td_elements = dom.getElementsByTagName(&quot;td&quot;)
remaining=&#039;&#039;
used=&#039;&#039;
for td in td_elements:
        temp = td.attributes.getNamedItem(&#039;class&#039;)
        if temp:
                if temp.value == &quot;savedTotal&quot;:
                        remaining=collect_text(td)
                if temp.value == &quot;usedTotal&quot;:
                        used=collect_text(td)

&lt;/code&gt;&lt;/pre&gt;

Now we have strings in our &quot;remaining&quot; and &quot;used&quot; variables which we can easily typecast to floats and process them further. I used some helper functions that I found on the net for dealing with number of days past and remaining in the month, I didn&#039;t note where they came from, so apologies to the author.

&lt;pre&gt;&lt;code&gt;print(&quot;Caluclating averages&quot;)
daysleft = 
    mkLastOfMonth(datetime.datetime.now())-datetime.datetime.now()
daysleft = daysleft.days
remaining_float = float(remaining)
used_float = -float(used)
days = int(datetime.datetime.now().strftime(&quot;%d&quot;))
&lt;/pre&gt;&lt;/code&gt;

Then, the magic...displaying the data as a notification bubble is flipping simple, you just import pynotify, initialise it with your namespace, and tell it what to display. You can get wrappers that allow you more flexibility for your notification (like images etc.), but I didn&#039;t need it.

&lt;pre&gt;&lt;code&gt;print(&quot;Displaying data&quot;)
usage=
   &quot;&lt;b&gt;%.2f Gb&lt;/b&gt; used in &lt;b&gt;%s&lt;/b&gt; days\nUsage average of &lt;b&gt;%.2f Mb&lt;/b&gt;&quot; % 
   (used_float,days,(used_float*1000)/days)

projected=
   &quot;\n\n&lt;b&gt;%s&lt;/b&gt; days left to use &lt;b&gt;%s Gb&lt;/b&gt;\ndaily allowance of &lt;b&gt;%.2f Mb&lt;/b&gt;&quot; % 
   (daysleft,remaining,(remaining_float*1000)/daysleft)

content = &#039;&#039;.join([usage,projected])
pynotify.init(&quot;cybersmart&quot;)
n = pynotify.Notification(&quot;Cybersmart Remaining Cap&quot;,content)
n.show()
&lt;/code&gt;&lt;/pre&gt;

It is not the most wonderful, or extensible code ever, but it works for me, and hopefully this can help someone else do something else. I would like to find a platform agnostic way to do notifications, and I have found some code to build a platform agnostic systray icon (which could keep track of you usage daily as a graph, and pop up a detailed notification when clicked). Splitting the code into classes would allow it to become more extensible in that multiple ISPs could be catered for using different approaches, with the same display code. 

I am stoked with how easy it was to roll it together (POSTing, downloading, parsing, processing and display in just over 30 lines), how easy it was to hook into libnotify (the freedesktop notification lib) for display. I have upgraded from edgy to feisty (which bumped python from 2.4 to 2.5) and it wasn&#039;t bothered either. You will need to install python-xml, and python-notify. The nice thing is that this is also an appropriate area for python, since it is just message passing.

&lt;add&gt;&lt;em&gt;Update 24/06/2007 - &lt;a href=&quot;http://vhata.rucus.net&quot;&gt;Jonathan&lt;/a&gt; pointed out &lt;a href=&quot;http://www.crummy.com/software/BeautifulSoup/&quot;&gt;BeautifulSoup&lt;/a&gt; as a more appropriate alternative to htmllib&lt;/em&gt;&lt;/add&gt;

As a side note, I fell in love with &lt;a href=&quot;http://www.python.org&quot;&gt;python&lt;/a&gt; when I learnt it so I could program in &lt;a href=&quot;http://www.djangoproject.com&quot;&gt;Django&lt;/a&gt;. I have slowly been trying to spread my python wings beyond simply writing web apps, because it is a flipping rad language, with awesome readability, and crazy power. I suppose you could say I script in python, because python is interpreted at run time, then all the java programmers are scriptors too, so ne ner ne ner ne ner. 
</description>
 <comments>http://whijo.net/blog/brad/2007/06/24/python-and-cybersmart-caps.html#comments</comments>
 <category domain="http://whijo.net/tags/cybersmart">cybersmart</category>
 <category domain="http://whijo.net/tags/geek">geek</category>
 <category domain="http://whijo.net/geek-tags/gnome">gnome</category>
 <category domain="http://whijo.net/tags/internet">internet</category>
 <category domain="http://whijo.net/tags/isp">ISP</category>
 <category domain="http://whijo.net/geek-tags/lazyweb">lazyweb</category>
 <category domain="http://whijo.net/geek-tags/libnotify">libnotify</category>
 <category domain="http://whijo.net/geek-tags/linux">linux</category>
 <category domain="http://whijo.net/geek-tags/python">python</category>
 <category domain="http://whijo.net/geek-tags/snippet">snippet</category>
 <category domain="http://whijo.net/geek-tags/tutorial">tutorial</category>
 <enclosure url="http://whijo.net/files/cybersmart.py_.txt" length="2433" type="text/plain" />
 <pubDate>Sun, 24 Jun 2007 10:07:17 +0200</pubDate>
 <dc:creator>brad</dc:creator>
 <guid isPermaLink="false">99 at http://whijo.net</guid>
</item>
<item>
 <title>Lazyweb, Lazyweb: Commandline hinting</title>
 <link>http://whijo.net/blog/brad/2007/06/19/lazyweb-lazyweb-commandline-hinting.html</link>
 <description>The geeks out there who use commandline on a popular set of operating systems (linux) may or may not know about bash_completion. bash_completion is awesome, it adds more tabbing to your typing. You type  ssh &amp;lt;tab&amp;gt; &amp;lt;tab&amp;gt;  and it starts suggesting what you might want to type, like hosts, or switches. It autocompletes when it can, and it makes life very easy. To the non-geek this translates into very efficient commandlines, and that is why geeks dig the commandline. I always thought bash_completion was awesome, but lacking a critical feature. bash_completion doesn&#039;t work for programs it doesn&#039;t know about. This is logical, because, how can it. So I propose, oh lazyweb, that we agree upon a switch like --hint for all commandline apps which spits out it&#039;s help in a form that an add on like bash completion can easily use, so even if bash_completion doesn&#039;t know about it, it can find out about it as you tab. It would allow richer things like this: 
&lt;code&gt;&lt;pre&gt;
yourhost$ ls -l &amp;lt;tab&amp;gt; &amp;lt;tab&amp;gt; 
       -l     use a long listing format
       Other Suggestions: ...
&lt;/pre&gt;&lt;/code&gt;

It would mean that everyone@opensource would need to figure out and agree upon a standard, but it would mean implementing hinting under different shells would be trivial to implement, and the problem gets farmed out to everyone who maintains their own packages, so hopefully we would see wider support.

It is just a rad geek dream, really. A lot like my tab completion IRC/IM/Blogging dream (the one where you hit a &amp;lt;tab&amp;gt; &amp;lt;tab&amp;gt; &amp;lt;tab&amp;gt; &amp;lt;tab&amp;gt; and it tells your friend what you want to say, without having to type it all out).</description>
 <comments>http://whijo.net/blog/brad/2007/06/19/lazyweb-lazyweb-commandline-hinting.html#comments</comments>
 <category domain="http://whijo.net/geek-tags/bash">bash</category>
 <category domain="http://whijo.net/tags/geek">geek</category>
 <category domain="http://whijo.net/geek-tags/lazyweb">lazyweb</category>
 <category domain="http://whijo.net/geek-tags/shell">shell</category>
 <category domain="http://whijo.net/geek-tags/wishlist">wishlist</category>
 <pubDate>Tue, 19 Jun 2007 11:53:13 +0200</pubDate>
 <dc:creator>brad</dc:creator>
 <guid isPermaLink="false">96 at http://whijo.net</guid>
</item>
</channel>
</rss>
